BroadcastReceiver 源码分析

1、动态注册过程源码分析:

在Activity中动态注册广播室,在注册方法之前其实省略了Context,也就是实际上调用的是Context.resgisterReceiver().Context是一个抽象类,它是Client端的AMS

,WMS、PMS等系统服务进行通信的接口,Activity、Service和Application都是继承它的子类。Context的实现类是ContextImpl,也就是说最终调用到的是ContextImpl中的registerReceiver()。

以下代码位于类ContextImpl中:

@OverridepublicIntentregisterReceiver(BroadcastReceiver receiver, IntentFilter filter) {//1接着回调用四个参数的registerReceiver()returnregisterReceiver(receiver, filter,null,null);    }@OverridepublicIntentregisterReceiver(BroadcastReceiver receiver, IntentFilter filter,            String broadcastPermission, Handler scheduler) {//2接着调用registerReceiverInternal()returnregisterReceiverInternal(receiver, getUserId(),                filter, broadcastPermission, scheduler, getOuterContext());    }privateIntentregisterReceiverInternal(BroadcastReceiver receiver,intuserId,            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();                }//3调用PackageInfo的getReceiverDispatcher()将广播接收者及其他参数封装成一个对象rd = mPackageInfo.getReceiverDispatcher(                    receiver, context, scheduler,                    mMainThread.getInstrumentation(),true);            }else{if(scheduler ==null) {                    scheduler = mMainThread.getHandler();                }                rd =newLoadedApk.ReceiverDispatcher(                        receiver, context, scheduler,null,true).getIIntentReceiver();            }        }try{//4ActivityManagerNative.getDefault()返回的其实是AMS在Client的代理对象returnActivityManagerNative.getDefault().registerReceiver(                    mMainThread.getApplicationThread(), mBasePackageName,                    rd, filter, broadcastPermission, userId);        }catch(RemoteException e) {returnnull;        }    }

注释1,2略。 

注释3:rd=mPackageInfo.getReceiverDispather(), mPakcageInfo(LoadedApk类声明)调用其getReceiverDispatcher()最终返回的是IIntentReceiver

.Stub类型的对象InnerReceiver,该类实现了IIntentReceiver接口并继承了Binder(显然就是AIDL中的stub部分)。在Android系统中,广播最终都是由AMS转送出来的。AMS利用Binder机制,而此处的rd对象正是承担传递工作的Binder实体。

为了方便管理这个binder实体,Android中定义了ReceiverDispatcher的类,每一个动态注册都会新建一个ReceiverDispatcher对象,并且这些对象保存在一个HashMap中,而这个HashMap又保存在LoadedApk中。

以下代码位于LoadedApk中

publicfinalclassLoadedApk{......staticfinalclassReceiverDispatcher{finalstaticclassInnerReceiverextendsIIntentReceiver.Stub{finalWeakReference mDispatcher;finalLoadedApk.ReceiverDispatcher mStrongRef;            InnerReceiver(LoadedApk.ReceiverDispatcher rd,booleanstrong) {                mDispatcher =newWeakReference(rd);                mStrongRef = strong ? rd :null;            }                    ......

在Android系统中,系统每加载一个apk,就会有一个LoadedApk对象。而每个LoadedApk对象里都会有一张HashMap,用来记录每个apk里面动态注册了那些广播接收者。

注释4:ActivityManagerNative.getDefault().registerReceiver()

作用将上述得到的rd等等数据发送给AMS。ActivityManagerNative.getDefault()得到的是ActivityManagerProxy紧接着会调用到ActivityManagerProxy中的registerReceiver();

一下代码位于类ActivityManagerProxy中

publicIntentregisterReceiver(IApplicationThreadcaller,StringpackageName,IIntentReceiverreceiver,IntentFilterfilter,Stringperm, int userId) throwsRemoteException{    //5封装数据到Parcel对象,并准备发送到AMSParceldata=Parcel.obtain();Parcelreply =Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller!=null?caller.asBinder(): null);data.writeString(packageName);data.writeStrongBinder(receiver!=null?receiver.asBinder(): null);filter.writeToParcel(data, 0);data.writeString(perm);data.writeInt(userId);//6,发射消息到AMS(此时开始切换线程从ClientThread到BinderThread)        mRemote.transact(REGISTER_RECEIVER_TRANSACTION,data, reply, 0);reply.readException();Intentintent = null;        int haveIntent = reply.readInt();if(haveIntent !=0) {            intent =Intent.CREATOR.createFromParcel(reply);        }        reply.recycle();data.recycle();return intent;    }

注释5:封装数据到Parcel对象data中,准备被binder 的代理对想mRemote发射到AMS

注释6:发送一个REGISTER_RECEIVER_TRANSACTION的进程间通信请求,此时开始切换线程。

接下来的过程就进入到AMS中了。首先流程进入到AMS中的registerReceiver(),(PS:其实是先到ActivityManagerNative,在ActivityManagerNative中对数据进行解包,然后调用到AMS中的

registerReceiver())

一下代码位于ActivityManagerService中:

publicfinalclassActivityManagerServiceextendsActivityManagerNative{......publicIntentregisterReceiver(IApplicationThread caller, String callerPackage,            IIntentReceiver receiver, IntentFilter filter, String permission,intuserId) {            ......//7得到请求注册的应用所在进程synchronized(this) {if(caller !=null) {                callerApp = getRecordForAppLocked(caller);            }            ......synchronized(this) {if(callerApp !=null&& (callerApp.thread ==null|| callerApp.thread.asBinder() != caller.asBinder()))returnnull;            }//8每次发来的一个注册请求都会对应ReceiverList 中的一条数据。ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());if(rl ==null) {                rl =newReceiverList(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) {returnsticky;                      ......//9创建一个BroadcastFilter 对象,BroadcastFilter 继承自IntentFilterBroadcastFilter bf =newBroadcastFilter(filter, rl, callerPackage,                        permission, callingUid, userId);                        rl.add(bf);if(!bf.debugCheck()) {                Slog.w(TAG,"==> For Dynamic broadcast");            }            mReceiverResolver.addFilter(bf);if(allSticky !=null) {                ArrayList receivers =newArrayList();                receivers.add(bf);}

注释7:得到是那一个进程请求注册广播接收者。

注释8:每一个BroadCastReceiver被注册的时候都会生成一个ReceiverList,每个ReceiverList都对应着Client端的一个ReceiverDispater(内含binder),如果rl为空那么调用

rl=new ReceiverList(this, callerApp, callingUid, userId, receiver); 其中参数Receiver为IIntentReceiver类型,其对应这receiverDispather传递过来的binder实体

对应关系在MRegisterReceivers中,其为一张HashMap。而每个ReceiverList里面保存的都是可以触发改BroadCastReceiver的IntentFilter(实际是BroadCastFilter,

原因BroadcastFilter 继承自IntentFilter).

注释9:创建一个BroadCastFilter对象bf,bf对应的是正在注册的广播接收者,紧接着rl.add(bf)把bf加入到mReceiverResolver和receivers中。当AMS收到广播的时候,AMS就会

通过其成员变量receivers找到该广播。

小结:

客户端方面:客户端广播注册的时候,LoadedApk对应着多个context对象(一个进程对应多个activity个service以及一个application),每个context里里面

有一张HashMap存放注册的广播接收者(每个activity里面可以注册过个广播,都存放在HashMap里),每张HashMap里面包含许多receiverDispatcher(内含binder)

AMS方面:每个client端的receiverDispatcher都对应一个receiverList,改receiverList中保存着可以启动该广播接收者的IntentFilter列表。而每一个ReceiverList

都对应这接收者注册时候的一个binder对象,如下:

final HashMapmRegisteredReceivers = new HashMap<>();

Client端和AMS端分别的对应图:

4.2静态注册

BroadCastReceiver静态注册指的是在AndroidManifest.xml中声明的接收者,在系统启动的时候,会由PackageManagerService(PMS)去解析。当AMS调用PMS的接口来查询广播注册的时候,PMS会查询记录并且返回给AMS

以下代码位于PackageManagerService中:

@OverridepublicListqueryIntentServices(Intent intent, String resolvedType,intflags,intuserId) {if(!sUserManager.exists(userId))returnCollections.emptyList();        ComponentName comp = intent.getComponent();if(comp ==null) {if(intent.getSelector() !=null) {                intent = intent.getSelector();                comp = intent.getComponent();            }        }if(comp !=null) {finalList list =newArrayList(1);finalServiceInfo si = getServiceInfo(comp, flags, userId);if(si !=null) {finalResolveInfo ri =newResolveInfo();                ri.serviceInfo = si;                list.add(ri);            }returnlist;        }synchronized(mPackages) {            String pkgName = intent.getPackage();if(pkgName ==null) {returnmServices.queryIntent(intent, resolvedType, flags, userId);            }finalPackageParser.Package pkg = mPackages.get(pkgName);if(pkg !=null) {returnmServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services,                        userId);            }returnnull;        }

PMS查询到的list集合返回给AMS,然后AMS依照集合内容执行操作。

4.3广播的发送

Android中发送广播,大致分为:无序广播sendBroadCast,有序光比sendOrderedBroadCast,粘广播sendStickyBroadCast。无序广播发送无序,注册过的接收者都能收到

有序广播对于接收者有一定的优先级,按照这种优先级依次往下发送,在这个过程中上级可以拦截发送到下一级别的广播;粘广播指的是未注册的接收者,一旦日后注册AMS,

那么还能够接收到错过的粘广播

sendBroadCast()同样具体实现是在ContextImpl中。

以下代码位于ContextImpl中:

@OverridepublicvoidsendBroadcast(Intent intent) {        warnIfCallingFromSystemProcess();        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());try{            intent.prepareToLeaveProcess();//10 拿到AMS的远程代理对象,准备发射到AMSActivityManagerNative.getDefault().broadcastIntent(                    mMainThread.getApplicationThread(), intent, resolvedType,null,                    Activity.RESULT_OK,null,null,null, AppOpsManager.OP_NONE,null,false,false,                    getUserId());        }catch(RemoteException e) {thrownewRuntimeException("Failure from system", e);        }    }

注释10:和注册BroadCastReceiver一样拿到AMS代理对象调用ActivityManagerProxy里面的broadcastIntent

一下代码运行在ActivityManagerProxy中:

public int broadcastIntent(IApplicationThreadcaller,Intentintent,StringresolvedType,IIntentReceiverresultTo,            int resultCode,StringresultData,Bundlemap,String[] requiredPermissions, int appOp,Bundleoptions, boolean serialized,            boolean sticky, int userId) throwsRemoteException{    //11写入数据到dataParceldata=Parcel.obtain();Parcelreply =Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller!=null?caller.asBinder(): null);intent.writeToParcel(data, 0);data.writeString(resolvedType);data.writeStrongBinder(resultTo!=null?resultTo.asBinder(): null);data.writeInt(resultCode);data.writeString(resultData);data.writeBundle(map);data.writeStringArray(requiredPermissions);data.writeInt(appOp);data.writeBundle(options);data.writeInt(serialized? 1 : 0);data.writeInt(sticky? 1 : 0);data.writeInt(userId);//12发送数据到AMS,(线程从ClientThread切换到BinderThread)        mRemote.transact(BROADCAST_INTENT_TRANSACTION,data, reply, 0);reply.readException();        int res = reply.readInt();        reply.recycle();data.recycle();return res;    }

注释11:和注册广播时候一样,把要发送的数据打包成Parcel对象data

注释12:发送数据到AMS,此时会切换成线程

接下来会执行AMS中的BroadCastIntent

一下代码位于ActivityManagerService中:

publicfinalintbroadcastIntent(IApplicationThread caller,            Intent intent, String resolvedType, IIntentReceiver resultTo,intresultCode, String resultData, Bundle resultExtras,            String[] requiredPermissions,intappOp, Bundle options,booleanserialized,booleansticky,intuserId) {        enforceNotIsolatedCaller("broadcastIntent");synchronized(this) {//13检查intent是否合法intent = verifyBroadcastLocked(intent);//14获取广播发送者的身份finalProcessRecord callerApp = getRecordForAppLocked(caller);finalintcallingPid = Binder.getCallingPid();finalintcallingUid = Binder.getCallingUid();finallongorigId = Binder.clearCallingIdentity();//15调用broadcastIntentLocked发送广播intres = broadcastIntentLocked(callerApp,                    callerApp !=null? callerApp.info.packageName :null,                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,                    requiredPermissions, appOp,null, serialized, sticky,                    callingPid, callingUid, userId);            Binder.restoreCallingIdentity(origId);returnres;        }    }

注释12 13 14 15 见代码

接着调用AMS的broadcastIntentLocked(),该方法主要用来查找目标广播接收者。

下面代码位于ActivityManagerService中:

privatefinalintbroadcastIntentLocked(ProcessRecord callerApp,            String callerPackage, Intent intent, String resolvedType,            IIntentReceiver resultTo,intresultCode, String resultData,            Bundle resultExtras, String[] requiredPermissions,intappOp, Bundle options,booleanordered,booleansticky,intcallingPid,intcallingUid,intuserId) {//16为intent添加FLAG_EXCLUDE_STOPPED_PACKAGES标记;intent =newIntent(intent);        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);            ......//17 处理和package相关的广播,处理其他一些系统广播,判断当前是否有权力发出广播。......//18判断是不是粘广播,并且如果要发送粘广播,那么就更新sticky广播列表。if(sticky) {if(checkPermission(android.Manifest.permission.BROADCAST_STICKY,                    callingPid, callingUid)                    != PackageManager.PERMISSION_GRANTED) {                String msg ="Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="+ callingPid +", uid="+ callingUid                        +" requires "+ android.Manifest.permission.BROADCAST_STICKY;                Slog.w(TAG, msg);thrownewSecurityException(msg);            }if(requiredPermissions !=null&& requiredPermissions.length >0) {                Slog.w(TAG,"Can't broadcast sticky intent "+ intent                        +" and enforce permissions "+ Arrays.toString(requiredPermissions));returnActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;            }if(intent.getComponent() !=null) {thrownewSecurityException("Sticky broadcasts can't target a specific component");            }if(userId != UserHandle.USER_ALL) {                ArrayMap> stickies = mStickyBroadcasts.get(                        UserHandle.USER_ALL);if(stickies !=null) {                    ArrayList list = stickies.get(intent.getAction());if(list !=null) {intN = list.size();inti;for(i=0; i list = stickies.get(intent.getAction());if(list ==null) {//如果不存在那么就创建一个listlist =newArrayList<>();//保存在stickies中stickies.put(intent.getAction(), list);            }finalintstickiesCount = list.size();inti;//for循环检查粘性广播list中是否存在与参数intent一致的广播for(i =0; i < stickiesCount; i++) {if(intent.filterEquals(list.get(i))) {//如果存在那么就用参数intent描述的广播替换它list.set(i,newIntent(intent));break;                }            }if(i >= stickiesCount) {//如果不存在就把intent描述的广播  加入到list中list.add(newIntent(intent));            }        }          ......//19判断发送给什么类型广播(静态注册还是动态注册)if((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)                ==0) {//到PMS找到静态注册的接收者保存在receivers中receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);        }if(intent.getComponent() ==null) {if(userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {                UserManagerService ums = getUserManagerLocked();for(inti =0; i < users.length; i++) {if(ums.hasUserRestriction(                            UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {continue;                    }                    List registeredReceiversForUser =                            mReceiverResolver.queryIntent(intent,                                    resolvedType,false, users[i]);if(registeredReceivers ==null) {                        registeredReceivers = registeredReceiversForUser;                    }elseif(registeredReceiversForUser !=null) {                        registeredReceivers.addAll(registeredReceiversForUser);                    }                }            }else{//找到动态注册的接受者并保存在registeredReceivers中registeredReceivers = mReceiverResolver.queryIntent(intent,                        resolvedType,false, userId);            }        }            }            ......//20封装广播finalbooleanreplacePending =                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) !=0;if(DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Enqueing broadcast: "+ intent.getAction()                +" replacePending="+ replacePending);intNR = registeredReceivers !=null? registeredReceivers.size() :0;if(!ordered && NR >0) {finalBroadcastQueue queue = broadcastQueueForIntent(intent);            BroadcastRecord r =newBroadcastRecord(queue, intent, callerApp,                    callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,                    appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,                    resultExtras, ordered, sticky,false, userId);if(DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Enqueueing parallel broadcast "+ r);finalbooleanreplaced = replacePending && queue.replaceParallelBroadcastLocked(r);if(!replaced) {                queue.enqueueParallelBroadcastLocked(r);                queue.scheduleBroadcastsLocked();            }            registeredReceivers =null;            NR =0;            ......            ......//21整理两个receiver列表        intNT = receivers !=null? receivers.size() :0;intit =0;            ResolveInfo curt =null;            BroadcastFilter curr =null;while(it < NT && ir < NR) {if(curt ==null) {                    curt = (ResolveInfo)receivers.get(it);                }if(curr ==null) {                    curr = registeredReceivers.get(ir);                }if(curr.getPriority() >= curt.priority) {// Insert this broadcast record into the final list.receivers.add(it, curr);                    ir++;                    curr =null;                    it++;                    NT++;                }else{// Skip to the next ResolveInfo in the final list.it++;                    curt =null;                }            }        }while(ir < NR) {if(receivers ==null) {                receivers =newArrayList();            }            receivers.add(registeredReceivers.get(ir));            ir++;        }            ......//22向接收者发送广播if((receivers !=null&& receivers.size() >0)                || resultTo !=null) {            BroadcastQueue queue = broadcastQueueForIntent(intent);            BroadcastRecord r =newBroadcastRecord(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());booleanreplaced = replacePending && queue.replaceOrderedBroadcastLocked(r);if(!replaced) {                queue.enqueueOrderedBroadcastLocked(r);                queue.scheduleBroadcastsLocked();            }        }returnActivityManager.BROADCAST_SUCCESS;    }

注释16:给intent添加FLAG_EXCLUDE_STOPPED_PACKAGES标记,如果一个应用在安装后从来没有启动过,或者已经被用户强制停止了,那么这个应用就处于停止状态,增加FLAG表示是否

要激活处于停止状态的应用,并发送广播给他们。

注释17:代码量很大,没有贴出来。该区间内的代码主要是处理package的广播,例如删除包的时候发送PACKAGE_REMOVED广播;其他系统广播发送,例如

PROXY_CHANGE_ACTION广播;还有判断当前应用示范有权利发送广播

注释18:sticky表示Intent描述的广播是不是一个粘广播,所有相同的粘广播都保存在一个相同的list中。其中的for循环,判断当前list中是否存在一个和参数intent一样的广播

吐过存在那么久用intent描述的广播来替代它,如果不存在就把该intent描述的广播添加到粘广播list中

注释19:把目标uangbo接收者分为两种类型:静态和动态,系统会到PMS中找到静态注册的广播接收者,并保存在Receiver中。receivers是利用PMS的queryIntentReceivers()

查询出和intent匹配的所有静态注册的广播接收者,此时所返回的查询结果本身已经排好序了。registerReceivers中的字项中保存的是动态注册的接收者,是没有经过排序的。

如果要并行发送广播那么registerReceivers中的各个子项会调用queue.scheduleBroadCastLocked()并行处理。如果要串行发送广播,那么必须把registerReceiver表合并到receivers表中

注释20:BroadcastRecord r = new BroadcastRecord()。将一个intent描述的广播,以及动态注册的广播接收者封装成一个BroadcastRecord 对象r,r描述的是AMS用来发送广播的一个任务。这个任务不是立马执行的。而是被加入到一个队列中,等待被执行。(发送广播要考虑广播是否是有序的,广播接收者本身也分静态注册和动态注册,静态广播接收者一般是有序的,而动态注册的广播接收者,则分情况),这里主要将并行的广播封装并插入BroadcastQueue内的并行处理队列。

注释21:此区间内的while循环主要用来合并动态注册和静态注册的广播接收者,合并后的广播接收者都保存在列表receivers中,并且是按照优先级排序的(剔除了并行广播后,合并之后的静态注册接收者和动态注册的接收者就按照顺序排放在一张表中)。

注释22:主要将参数intent所描述的广播,以及剩余的其他广播封装成一个BroadcastRecord对象r,r就是AMS要执行的一个广播转发任务并且加入到AMS的内部有序广播队列中该段代码,主要new一个BroadcastRecord节点,并插入BroadcastQueue内的串行处理队列,最后调用实际的广播发行方法scheduleBroadcastsLocked()。

接下来就执行scheduleBroadcastsLocked()方法。

以下代码位于BroadcastQueue中:

//23发送消息publicvoidscheduleBroadcastsLocked() {if(DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Schedule broadcasts ["+ mQueueName +"]: current="+ mBroadcastsScheduled);//为true说名ams的mq中已经有BROADCAST_INTENT_MSG的消息if(mBroadcastsScheduled) {return;        }//否则就发送消息mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG,this));        mBroadcastsScheduled =true;    }

注释23:mBroadcastsScheduled是AMS的一个成员变量,用来记录AMS是否已经向其所在线程的消息队列发过一条BROADCAST_INTENT_MSG的消息。如果为true说明AMS所在消息队列已经有一个BROADCAST_INTENT_MSG的消息,反之则调用mHandler发送该条消息到AMS所在线程消息队列。最后将mBroadcastsScheduled 设置为true,表明该广播已经成功发送出去了(ps:这个阶段广播只是被发送到了AMS所在线程的消息队列,并没有真正到广播接收者手中,也就是表明当广播被发送到AMS的时候系统会认为广播已经发送成功)。

既然是handler发送的消息,那么处理消息的肯定在handleMessage中处理的。

以下代码位于BroadcastQueue中:

@OverridepublicvoidhandleMessage(Message msg) {switch(msg.what) {//24 处理消息caseBROADCAST_INTENT_MSG: {if(DEBUG_BROADCAST) Slog.v(                            TAG_BROADCAST,"Received BROADCAST_INTENT_MSG");                    processNextBroadcast(true);                }break;caseBROADCAST_TIMEOUT_MSG: {synchronized(mService) {                        broadcastTimeoutLocked(true);                    }                }break;caseSCHEDULE_TEMP_WHITELIST_MSG: {                    DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController;if(dic !=null) {                        dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1),                                msg.arg2,true, (String)msg.obj);                    }                }break;            }        }

注释24:调用processNextBroadcast来处理类型为BROADCAST_INTENT_MSG的消息

以下代码位于BroadcastQueue中:

finalvoidprocessNextBroadcast(booleanfromMsg) {......if(fromMsg) {//fromMsg表示是否为BROADCAST_INTENT_MSG类型的消息mBroadcastsScheduled =false;            }//25处理mParallelBroadcasts中的广播转发任务while(mParallelBroadcasts.size() >0) {                r = mParallelBroadcasts.remove(0);                r.dispatchTime = SystemClock.uptimeMillis();                r.dispatchClockTime = System.currentTimeMillis();finalintN = r.receivers.size();if(DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,"Processing parallel broadcast ["+ mQueueName +"] "+ r);for(inti=0; i

注释25:while循环处理保存在mParallelBroadcasts中的广播转发任务,mParallelBroadcasts是无序广播队列。

//26处理AMS有序调度队列morderedbroadcast  if (mPendingBroadcast != null) {                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,"processNextBroadcast ["+ mQueueName +"]: waiting for "+ mPendingBroadcast.curApp);boolean isDead;synchronized (mService.mPidsSelfLocked) {                    ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);isDead = proc == null || proc.crashing;}              //如果正在启动 ams就wait                if (!isDead) {                    return;} else {                    // 否则就准备想它发送广播                    Slog.w(TAG,"pending app  ["+ mQueueName +"]"+ mPendingBroadcast.curApp+" died before responding to broadcast");mPendingBroadcast.state= BroadcastRecord.IDLE;mPendingBroadcast.nextReceiver= mPendingBroadcastRecvIndex;mPendingBroadcast = null;}            }            //27do {                if (mOrderedBroadcasts.size() ==0) {            //广播已经处理完了                    mService.scheduleAppGcsLocked();if (looped) {                        mService.updateOomAdjLocked();}                    return;}    //广播未处理完取出来存放在r中                r = mOrderedBroadcasts.get(0);boolean forceReceive = false;int numReceivers = (r.receivers!= null) ? r.receivers.size() :0;if (mService.mProcessesReady&& r.dispatchTime>0) {                    long now = SystemClock.uptimeMillis();if ((numReceivers >0) &&                            (now > r.dispatchTime+ (2*mTimeoutPeriod*numReceivers))) {                        Slog.w(TAG,"Hung broadcast ["+ mQueueName +"] discarded after timeout failure:"+" now="+ now                                +" dispatchTime="+ r.dispatchTime+" startTime="+ r.receiverTime+" intent="+ r.intent+" numReceivers="+ numReceivers                                +" nextReceiver="+ r.nextReceiver+" state="+ r.state);broadcastTimeoutLocked(false); // forcibly finish this broadcastforceReceive = true;r.state= BroadcastRecord.IDLE;}                }                if (r.state!= BroadcastRecord.IDLE) {                    if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,"processNextBroadcast("+ mQueueName +") called when not idle (state="+ r.state+")");return;}                if (r.receivers== null || r.nextReceiver>= numReceivers                        || r.resultAbort|| forceReceive) {                    if (r.resultTo!= null) {                        try {                            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,"Finishing broadcast ["+ mQueueName +"] "+ r.intent.getAction() +" app="+ r.callerApp);performReceiveLocked(r.callerApp, r.resultTo,                                new Intent(r.intent), r.resultCode,                                r.resultData, r.resultExtras, false, false, r.userId);mBroadcastHistory.                            r.resultTo= null;} catch (RemoteException e) {                            r.resultTo= null;Slog.w(TAG,"Failure ["+ mQueueName +"] sending broadcast result of "+ r.intent, e);}                    }                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Cancelling BROADCAST_TIMEOUT_MSG");cancelBroadcastTimeoutLocked();if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,"Finished with ordered broadcast "+ r);addBroadcastToHistoryLocked(r);mOrderedBroadcasts.remove(0);r = null;looped = true;continue;}            } while (r == null);......

注释26:有序广播中,目标广播有可能是静态的。要是静态注册的广播进程还未启动起来。那么AMS就将其进程启动起来,然后发送广播给广播接收者。

注释27:在有序调度队列mOrderedBroadcasts中找到下一个需要处理的广播转发任务。while循环当r!=null的时候跳出循环,这时候下一个需要处理的广播就保存在r中,这时候AMS就对其进行处理 ,同样调用到方法deliverToRegisteredReceiverLocked(r, filter, r.ordered);

接着程序运行到deliverToRegisteredReceiverLocked()。

以下代码位于BroadcastQueue中:

...... private void deliverToRegisteredReceiverLocked(BroadcastRecord r,            BroadcastFilter filter, boolean ordered) {    try {                if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,"Delivering to "+ filter +" : "+ r);//28将broadcast 的对象r 描述的广播转发给broadcastFilter处理                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,                        new Intent(r.intent), r.resultCode, r.resultData,                        r.resultExtras, r.ordered, r.initialSticky, r.userId);if (ordered) {                    r.state= BroadcastRecord.CALL_DONE_RECEIVE;}            } catch (RemoteException e) {                Slog.w(TAG,"Failure sending broadcast "+ r.intent, e);if (ordered) {                    r.receiver= null;r.curFilter= null;filter.receiverList.curBroadcast= null;if (filter.receiverList.app!= null) {                        filter.receiverList.app.curReceiver= null;}                }            }......

注释28:deliverToRegisteredReceiverLocked方法中系统在检查广播发送者和接收者的权限之后,最后将BroadcastRecord对象r描述的广播交给BroadcastFilter处理。接着调用performReceiveLocked()方法。

以下代码位于BroadcastQueue中:

privatestaticvoidperformReceiveLocked(ProcessRecord app, IIntentReceiver receiver,            Intent intent,intresultCode, String data, Bundle extras,booleanordered,booleansticky,intsendingUser)throwsRemoteException {if(app !=null) {if(app.thread !=null) {//29调用到ApplicationThreadProxy中的scheduleRegisteredReceiver方法app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,                        data, extras, ordered, sticky, sendingUser, app.repProcState);            }else{thrownewRemoteException("app.thread must not be null");            }        }else{            receiver.performReceive(intent, resultCode, data, extras, ordered,                    sticky, sendingUser);        }

注释29:app.thread对应的就是ApplicationThreadProxy,该类是ApplicationThreadNative的内部类。

以下代码位于ApplicationThreadProxy中:

public final void scheduleReceiver(Intentintent,ActivityInfoinfo,CompatibilityInfocompatInfo, int resultCode,StringresultData,Bundlemap, boolean sync, int sendingUser, int processState) throwsRemoteException{Parceldata=Parcel.obtain();data.writeInterfaceToken(IApplicationThread.descriptor);intent.writeToParcel(data, 0);info.writeToParcel(data, 0);compatInfo.writeToParcel(data, 0);data.writeInt(resultCode);data.writeString(resultData);data.writeBundle(map);data.writeInt(sync? 1 : 0);data.writeInt(sendingUser);data.writeInt(processState);//30远程跨进程发送数据        mRemote.transact(SCHEDULE_RECEIVER_TRANSACTION,data, null,IBinder.FLAG_ONEWAY);data.recycle();}

注释30:远程Binder对象发送Parcel  类型数据到ApplicationThread。接着调用到ApplicationThread中的scheduleRegisteredReceiver()。ApplicationThread是ActivityThread的内部类。

以下代码位于ApplicationThread中:

publicvoidscheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,intresultCode, String dataStr, Bundle extras,booleanordered,booleansticky,intsendingUser,intprocessState)throwsRemoteException {            updateProcessState(processState,false);//receiver指向一个InnerReceiver 对象,每个InnerReceiver对象封装了一个广播接收者receiver.performReceive(intent, resultCode, dataStr, extras, ordered,                    sticky, sendingUser);        }

接着调用InnerReceiver 中的performReceive()方法。

以下代码位于InnerReceiver类中,InnerReceiver又位于类loadedApk中:

publicvoidperformReceive(Intent intent,intresultCode, String data,                    Bundle extras,booleanordered,booleansticky,intsendingUser) {                LoadedApk.ReceiverDispatcher rd = mDispatcher.get();if(ActivityThread.DEBUG_BROADCAST) {intseq = intent.getIntExtra("seq", -1);                    Slog.i(ActivityThread.TAG,"Receiving broadcast "+ intent.getAction() +" seq="+ seq                            +" to "+ (rd !=null? rd.mReceiver :null));                }if(rd !=null) {//31 调用rd的performReceiverd.performReceive(intent, resultCode, data, extras,                            ordered, sticky, sendingUser);                }else{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) {                        Slog.w(ActivityThread.TAG,"Couldn't finish broadcast to unregistered receiver");                    }                }            }        }

注释31:接着调用到rd的performReceive()。rd是ReceiverDispatcher的对象。还记得ReceiverDispatcher么?在注册广播的时候每个Client端的ReceiverDispatcher都对应一个ReceiverList,

接着调用到ReceiverDispatcher的performReceive(),ReceiverDispatcher是loadedApk的内部类。

以下代码位于ReceiverDispatcher中:

publicvoidperformReceive(Intent intent,intresultCode, String data,                Bundle extras,booleanordered,booleansticky,intsendingUser) {if(ActivityThread.DEBUG_BROADCAST) {intseq = intent.getIntExtra("seq", -1);                Slog.i(ActivityThread.TAG,"Enqueueing broadcast "+ intent.getAction() +" seq="+ seq                        +" to "+ mReceiver);            }            Args args =newArgs(intent, resultCode, data, extras, ordered,                    sticky, sendingUser);//32 mActivityThread 是一个handler 对象指向ActivityThread中的handler对象if(!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);                }            }        }

注释32:调用mActivityThread.post(args)方法,mActivityThread是一个Handler对象,该对象指向ActivityThread中的mH;因此此刻切换到广播接收者所在进程的主线程来执行args,args是一个Runnable对象。

以下代码位于Args 中:

finalclassArgsextendsBroadcastReceiver.PendingResultimplementsRunnable{......publicvoidrun() {finalBroadcastReceiver receiver = mReceiver;finalbooleanordered = mOrdered;if(ActivityThread.DEBUG_BROADCAST) {intseq = mCurIntent.getIntExtra("seq", -1);                    Slog.i(ActivityThread.TAG,"Dispatching broadcast "+ mCurIntent.getAction()                            +" seq="+ seq +" to "+ mReceiver);                    Slog.i(ActivityThread.TAG,"  mRegistered="+ mRegistered                            +" mOrderedHint="+ ordered);                }finalIActivityManager mgr = ActivityManagerNative.getDefault();finalIntent intent = mCurIntent;                mCurIntent =null;if(receiver ==null|| mForgotten) {if(mRegistered && ordered) {if(ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing null broadcast to "+ mReceiver);                        sendFinished(mgr);                    }return;                }                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"broadcastReceiveReg");try{                    ClassLoader cl =  mReceiver.getClass().getClassLoader();                    intent.setExtrasClassLoader(cl);                    setExtrasClassLoader(cl);                    receiver.setPendingResult(this);//33 receiver指向的是我们自己继承的broadcastreceiver因此调用到我们写的onReceive方法receiver.onReceive(mContext, intent);                }catch(Exception e) {if(mRegistered && ordered) {if(ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing failed broadcast to "+ mReceiver);//34通知ams 转发出来的广播已经处理完成sendFinished(mgr);                    }if(mInstrumentation ==null||                            !mInstrumentation.onException(mReceiver, e)) {                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);thrownewRuntimeException("Error receiving broadcast "+ intent                            +" in "+ mReceiver, e);                    }                }if(receiver.getPendingResult() !=null) {                    finish();                }                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);            }  ......  }

注释33:此刻的receiver指向的是我们自己定义的BroadcastReceiver的子类例如上文的MyReceiver,此时调用的  receiver.onReceive()就是我们在MyReceiver中重写的onReceive()。

注释34:通知AMS,转发出来的广播以执行完毕。

以上就是关于Android的注册和发送广播,到最后执行的到广播接收者onReceive()方法的所有流程。

总结:BroadcastReceiver其核心机制是基于Bind的IPC通信,一个广播接收者要想接收到广播,必须注册到AMS中,在AMS中有ReceiverList保存注册的广播接收者。发送广播到AMS时候,

AMS会查找相应的BroadcastFilter,匹配就会调用相应的远程Binder代理对象通知Client端,最终由Client端的主线程来执行MyReceiver里面的onReceiver()方法。发送广播的又分为有序和无序,

无序一定是动态注册的,而有序可能是动态注册的也可能是静态注册的。静态注册的广播,那怕是没有启动,如果AMS递送相关广播,则会先启动该进程然后递送。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容