onreceive 分析广播 的 registerReceiver、sendBroadcast、 onReceive 系统到底做了什么?

新闻热点

介绍

广播接收器(BroadcastReceiver)是Android的四大组件之一,它作为应用程序和进程之间的重要通信方式,可以通过广播向订阅的广播接收器传输消息。我们来分析一下,广播注册接收消息后,Android源代码做了什么。

源代码解析寄存器接收器时序图

代码解释

让我们按照上面的时序图来解释代码

首先在主活动注册接收器中广播接收器

publicclass mainactivityextendsactivity {

@覆盖

受保护的无效创建(捆绑保存的实例){

super . OnCreate(SaveDinstancestate);

setContentView(r . layout . activity _ main);

//注册广播接收器

register receiver(new receiver Rb,filter b);

}

...省略代码...

}

单击注册接收者,我们发现它不是活动中的方法,而是活动的父类上下文包装器

上下文包装注册接收器

publicClassActivityExtendsContextThemewrapper

implementsLayoutInflater。因子2,

窗户。回调,KeyEvent。回调,

OnCreateContextMenuListener,ComponentCallbacks2,

窗户。在OnWindowDismissedCallback,WindowControllerCallback,

自动映射管理器。自动链接{

...省略代码...

}

publicclasscontextthewrapperextendcontextwrapper {

...省略代码...

}

publicClassContextwrapperextendsContext {

@覆盖

publicationRegisterReceiver(

广播接收器接收器,内部过滤器过滤器){

returnmbase . register receiver(receiver,filter);

}

}

这里的成员变量是上下文。在阅读了应用程序启动块的源代码之后,我们知道ContextImp继承了Context,所以让我们来看看继承类的具体的registerReceiver方法。

上下文输入注册接收器

classContextImplextendsContext {

@覆盖

公共意图注册接收器(广播接收器接收器,内部过滤器过滤器,

String broadcastPermission,Handler scheduler,intflags){

returnregisterReceiverInternal(接收方,getUserId,

过滤器、broadcastPermission、调度器、getOuterContext、标志);

}

}

继续查看注册表

private intent register receiverinternal(广播接收器接收器,输入字符串,

内部筛选器筛选器,字符串广播权限,

处理程序调度程序,上下文上下文,intflags){

IIntentReceiver rd = null

if(接收器!= null) {

if(MpackainFo!= null & amp& amp上下文!= null) {

if(scheduler == null) {

//获取activitythread H。

scheduler = MMINTHread . GetHandler;

}

//获取IIntentReceiver对象,通过它与AMS交互,通过Handler传递消息

rd = mpackageeinfo . getreceiverdispatcher(

接收器、上下文、调度器,

mMainThread.getInstrumentation,true

} else{

if(scheduler == null) {

scheduler = MMINTHread . GetHandler;

}

rd = newLoadedApk。ReceiverDispatcher(

接收器、上下文、调度器、空、真)。getIIntentReceiver

}

}

尝试{

//调用AMS的registerReceiver

final intent = activity manager . GetServiCe . register receiver(

mmain thread . getapplicationthread,mBasePackageName,rd,filter,

broadcastPermission、userId、flags);

if(intent!= null) {

intent . setextraclasloader(GetClassLoader);

intent.prepareToEnterProcess

}

returnintent

} catch(RemoteException e) {

throwe.rethrowFromSystemServer

}

}

注册广播接收方的函数最后进入ContextImpl的registerReceiverInternal函数,其中成员变量mPackageInfo是LoadApk实例,负责处理广播的接收。

练习阅读

由mMainThread.getHandler获得的处理程序用于分发AMS发送的广播。

privateclassHextendsHandler{

...

publicvoidhandleMessage(消息消息){

案例接收者:

handleReceiver((receiver data)msg . obj);

maybeSnapshot

打破;

}

....

}

继续看手柄接收器

privatevoid handleReceiver(接收数据){

....

//应用应用程序局部变量

应用app

//广播局部变量

广播接收器;

//应用上下文

ContextImpl上下文;

尝试{

//进行应用

app = package info . make application(false,mInstrumentation);

//获取上下文

context =(Context impl)app . GetBaseContext;

if( data.info.splitName!= null) {

context =(context impl)context . createcontextforsplit(data . info . split name);

}

Java . lang . ClassLoader cl = context . GetClassLoader;

data . intent . SetExtrasclassLoader(cl);

data . intent . preparetointerprocess;

data . setextraclassloader(cl);

//通过反射实例化广播

receiver =(BroadcastReceiver)cl . LoAdClass(组件)。newInstance

}捕获(例外e) {

尝试{

if(localLOGV) Slog.v(

sCurrentBroadcastIntent。set(data . intent);

receiver.setPendingResult(数据);

//接收呼叫

receiver . onreceive(context . getreceiverrestricted context,

data . intent);

}捕获(例外e) {

...

}最后{

sCurrentBroadcastIntent。set(null);

}

....

}

mpackageinfo的实现。getreceiveddispatcher函数

//LoadeApk

publicinitentreceiver getReceiverDispatcher(BroadcastReceiver r,

上下文上下文,处理程序,

仪器仪表,布尔注册){

同步(mReceivers) {

LoadedApk。ReceiverDispatcher rd = null

ArrayMap&lt。BroadcastReceiver,LoadedApk。ReceiverDispatcher&gt。map = null

if(注册){

map = mrecereivers . get(context);

if( map!= null) {

rd = map . get(r);

}

}

if(rd == null) {

rd = newReceiverDispatcher(r,context,handler,

仪器仪表,已注册);

if(注册){

if( map== null) {

map= newArrayMap&lt。BroadcastReceiver,LoadedApk。ReceiverDispatcher&gt。;

//以上下文为关键字,映射为值,存储在邮件传递中

mrecereivers . put(context,map);

}

map.put(r,rd);

}

} else{

rd.validate(上下文,处理程序);

}

rd.mForgotten = false

returnrd.getIIntentReceiver

}

}

在loaded PK类的getReceivcerDispatcher函数中,首先检查r是否已经被实例化,如果没有,创建一个,保存在一个以r为键值的HM集中,这个映射存储在mReceivers中,所以只要给定一个Activity和一个BroadcastReceiver,就可以检查loaded PK中是否有对应的广播接收者和发布者。

现在回到contextimpl。registerreceiverinternal函数,并获取IIntentReceiver类型的Binder对象,它开始在AMS中注册。具体代码见下面小点。

AMS注册接收器

/**

*这由活页夹通知调用。

* @返回意向

*/

公共意图注册接收器(应用线程调用程序,字符串调用程序包,

输入接收器接收器,内部过滤器过滤器,字符串允许,输入,

intflags) {

enforceNotIsolatedCaller(" RegisterReceiver ");

ArrayList&lt。意图。stickyIntents = null

ProcessRecord callerApp拉普= null

最终布尔visibleToInstantApps

=(旗帜和。语境。RECEIVER _ VISIBLE _ TO _ INSTANT _ APPS)!= 0;

intcallingUid

intcallingPid

boolean instantApp

同步(此){

if(caller!= null) {

//1.进入ProcessRecord

caller拉普= getRecordForAppLocked(调用者);

if(callerApp == null) {

...省略代码...

}

...省略代码...

//2.根据动作找到匹配的粘性接收器

迭代器&lt。字符串>actions = filter . actionsiterator;

if(actions == null) {

ArrayList&lt。字符串>noAction = newArrayList & lt字符串>( 1);

noAction . add(null);

actions = noAction.iterator

}

...省略代码...

//3.获取接收列表

receiver list rl = Mregisteredrereceivers。get(receiver . Asbinder);

if(rl == null) {

rl = newReceiverList( this,callerApp拉普,callingPid,callingUid,

userId,receiver);

if(rl.app!= null) {

rl . app . receivers . add(rl);

} else{

尝试{

receiver . as binder . LinkTodEath(rl,0);

} catch(RemoteException e) {

returnsticky

}

rl.linkedToDeath = true

}

mregisteredrecevenuers . put(receiver . as binder,rl);

} elseif(rl.uid!= callingUid) {

...省略代码...

}

//4.构建BroadcastFilter对象,并将其添加到接收列表中

BroadcastFilter BF = new roadcastfilter(filter,rl,callerPackage,

权限、callingUid、userId、instantApp、visibletoinstant apps);

rl . add(BF);

if(!bf.debugCheck) {

Slog.w(TAG," = = >;对于动态广播");

}

mreciverresolver . AddFilter(BF);

...省略代码...

returnsticky

}

}

根据上面注1,得到流程对应的PID和uid

注2获得所有行动;IntentFilter的;

注3将广播接收机的接收机保存在一个ReceiverList中,这个列表的主机进程是rl.app,也就是MainActivity所在的进程。

注释4仅保存广播接收器,但它尚未与过滤器相关联。在这里,创建一个BroadcastFilter,将广播接收器列表rl与过滤器相关联,然后将其保存在AMS成员变量mReceiverResolver中。这样,将要接收的广播类型的广播接收器和接收器过滤器将被保存在AMS中,并且稍后可以接收和处理相应的广播。

接下来,让我们来看一下发送广播。

接收时序图

最后,当Activity通过sendBroadcast发送广播时,Binder将其发送给AMS,AMS根据广播的Action类型找到相应的广播接收器,然后将广播放入自己的消息队列中,完成广播第一部分的异步分发。

最终广播内容锁定(进程记录调用,

字符串调用包,意图,字符串求解类型,

IIntentReceiver resultTo,intresultCode,StringresultData,

捆绑结果附加项,字符串[]需要权限,支持,捆绑选项,

boolean ordered,boolean sticky,intcallingPid,intcallingUid,intuserId) {

意图=新意图(intent);

.....省略代码....

if(intent.getComponent == null) {

.....省略代码....

} else{

//与此意向对应的BroadcastFilter也是接收方列表。

registeredrereceiver = mreciverresolver . query intent(intent,

resolvedType,false/*defaultOnly*/,UserID);

}

}

.....省略代码....

if(!替换){

queue . EnqueryParallelbroadcastLocked(r);

//处理广播分发

queue . schedulebroadcastslocked;

}

registeredReceivers = null

NR = 0;

}

.....省略代码....

returnActivityManager。BROADCAST _ SUCCESS

}

AMS在消息循环中处理该广播,并通过绑定机制将其分发到注册的接收空间。ReceiverDispatch将此广播放入MainActivity所在进程的消息队列中,并完成异步消息分发的第二部分。

publicationschedulebroadcastsLocked {

if(DEBUG _ BROAT)slog . v(TAG _ BROAT,“安排广播[”

+ mQueueName + "]:当前= "

+MBRoadcastsScheduled);

if(mBroadcastsScheduled) {

返回;

}

//通过处理程序分发

MH handler . send message(MH handler . get message(BROADCAST _ INTENT _ MSG,this));

mBroadcastsScheduled = true

}

privatefileclass broadcasthandlerxendshandler {

......

@覆盖

publicvoidhandleMessage(消息消息){

switch(msg.what) {

caseBROADCAST_INTENT_MSG: {

if(DEBUG _ BROAT)slog . v(

标签_广播,“接收的广播_意图_消息”);

//处理下一个广播

processNextBroadcast(true);

} break

....

}

}

}

ReceiverDispatch的内部类Args在MainActivity所在的线程消息循环中处理此广播,并最终将此广播分发到注册的接收器实例的接收方处理中。

publicfinalclassLoadedApk {

...

statifindclassreceiverdispatcher {

finalclasargesetndsbloadcastreceiver。PendingResult{

....

public finallyrunnable GetRunnable {

return->{

....

尝试{

class loader cl = Mr receiver . GetClass . GetClass loader;

intent . setextraclassloader(cl);

intent.prepareToEnterProcess

setextraclassloader(cl);

receiver . SetpendingResult(this);

//回拨到接收广播的接收器

receive(McContext,intent);

}捕获(例外e) {

...

};

}

}

}

...

}

总结

注册和接收源码分析差不多到了。简单来说,广播就是一个订阅-发布的过程。广播接收器通过一些地图存储,关键是封装这些广播的信息类,如Action。发布广播时,通过AMS查询该地图中广播的IntentFilter注册的BroadcastReceiver,然后通过ReceiverDispatch将广播分发到所有订阅的对象,从而完成整个通信过程。

感谢阅读。谢谢!

链接:https://juejin.im/post/5d752aad518825346e5f2b31

标签: onreceive