Android 广播的注册流程

Android 广播的注册流程

引言

广播是一种典型的发布/订阅模式,消息的生产者发布消息,而接收者订阅感兴趣的信息。高内聚低耦合性是判断软件设计好坏的标准,Broadcast把高内聚低耦合做得非常好,当你想发送广播的时候,你根本不用知道接收者的名字,也不用关心谁来接收,你只管发消息即可。

由图可知:广播主要分为三个阶段。第一个阶段:广播接收者APP1、APP2、APP3先往AMS注册感兴趣的广播。第二个阶段:广播发送者APP4发送一个广播。第三个阶段:AMS查找谁对APP4发送的广播感兴趣,找到后就把广播发送给对其感兴趣的广播接收者APP1、APP2、APP3.

应用层如何注册动态广播

private static final String TAG = "TEST_BROADCAST";

public static final String ACTION_TEST_BROADCAST = "android.intent.action.TEST_BROADCAST";

public static final String ACTION_TEST_BROADCAST2 = "android.intent.action.TEST_BROADCAST2";

private void registerReceiver() {

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction(ACTION_TEST_BROADCAST);

intentFilter.addAction(ACTION_TEST_BROADCAST2);

registerReceiver(mBroadcastReceiver,intentFilter);

}

public static BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

if (intent.getAction().equals(ACTION_TEST_BROADCAST)){

Log.d(TAG, "mBroadcastReceiver onReceive action = " + ACTION_TEST_BROADCAST);

} else if (intent.getAction().equals(ACTION_TEST_BROADCAST2)){

Log.d(TAG, "mBroadcastReceiver onReceive action = " + ACTION_TEST_BROADCAST2);

}

}

};

@Override

protected void onDestroy() {

super.onDestroy();

unregisterReceiver(mBroadcastReceiver);

}

通过方法registerReceiver注册一个广播。它需要两个参数,第一个参数类型是BroadcastReceiver,第二个参数类型是IntentFilter。BroadcastReceiver用来接收广播,IntentFilter用来存放广播的Action等信息。目的在将Action与BroadcastReceiver进行绑定,Action与BroadcastReceiver在这里是多对一的关系,在其他场景下可能是多对多的关系。

流程分析

应用进程部分

registerReceiver是广播进行注册的核心方法,我们看看这个方法的调用过程。registerReceiver调用的是定义在ContextWrapper中的方法。

@Override

public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {

return mBase.registerReceiver(receiver, filter);

}

ContextWrapper类中的registerReceiver方法又调用了mBase对象的registerReceiver,mBase指的是ContextImpl对象。

@Override

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {

return registerReceiver(receiver, filter, null, null);

}

两个参数的会调用4个参数的。其中broadcastPermission和Handler类型的数据传入null。

@Override

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,

String broadcastPermission, Handler scheduler) {

return registerReceiverInternal(receiver, getUserId(),

filter, broadcastPermission, scheduler, getOuterContext(), 0);

}

registerReceiver又会调用registerReceiverInternal。这里增加了三个参数。第一个getUserId()是进程的userid,第二个getOuterContext()是MainActivity对象,第三个flags是一个int类型的值,这里传入的是0. 我们看下registerReceiverInternal。

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,

IntentFilter filter, String broadcastPermission,

Handler scheduler, Context context, int flags) {

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 = ActivityManager.getService().registerReceiver(

mMainThread.getApplicationThread(), mBasePackageName, rd, filter,

broadcastPermission, userId, flags);

if (intent != null) {

intent.setExtrasClassLoader(getClassLoader());

intent.prepareToEnterProcess();

}

return intent;

} catch (RemoteException e) {

throw e.rethrowFromSystemServer();

}

}

receiver是前面传递过来的BroadcastReceiver类型的对象,它不为空,第一个if条件成立。context是getOuterContext的值,值为MainActivity对象,也不为空。变量mPackageInfo是一个LoadedApk类型的变量,它用来负责处理广播的接收,发送广播之后会经过它分发出去,它也不为空(这个的赋值过程以后再讲,我们着眼于重点部分),所以if (mPackageInfo != null && context != null) {成立。scheduler为空,因为传递的过程中赋值给null,所以这里scheduler会通过mMainThread的getHandler方法获得Handler对象,这个Handler就是ActivityThread中的Handler对象,也就是主线程的Handler对象。接着,会通过mPackageInfo的getReceiverDispatcher获取一个IIntentReceiver类型的对象rd,它是一个binder对象。

我们看下getReceiverDispatcher方法。它一共有5个参数,分别是BroadcastReceiver类型的对象,MainActivity对象,Handler对象,Instrumentation对象,以及一个bool类型的变量。

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,

Context context, Handler handler,

Instrumentation instrumentation, boolean registered) {

synchronized (mReceivers) {

LoadedApk.ReceiverDispatcher rd = null;

ArrayMap 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 ArrayMap();

mReceivers.put(context, map);

}

map.put(r, rd);

}

} else {

rd.validate(context, handler);

}

rd.mForgotten = false;

return rd.getIIntentReceiver();

}

}

private final ArrayMap> mReceivers

= new ArrayMap<>();

这里首先会拿一把锁mReceivers,mReceivers如上,是一个ArrayMap数组,key是Context类型的,value也是一个ArrayMap,k是BroadcastReceiver类型,v是ReceiverDispatcher类型。

接着看第一个if,registered是传递进来的,是true,所以这个条件成立,条件成立就会去mReceivers中查找是否有以传入进来的context对象为key的value,如果有取出这个value,也就是ArrayMap,接着看是否有以当前传入进来的BroadcastReceiver对象为key的value,也就是LoadedApk.ReceiverDispatcher。然后进入第二个判断条件,如果LoadedApk.ReceiverDispatcher对象为null,也就是ArrayMap不存在以BroadcastReceiver对象为key,LoadedApk.ReceiverDispatcher为value的数据,这个时候就会new一个ReceiverDispatcher对象。因为if (registered) {为true,接下来往mReceivers存入Context、BroadcastReceiver、ReceiverDispatcher,当然这里的Context就是MainActivity对象。说这么多,其实就是将MainActivity对象,BroadcastReceiver对象,ReceiverDispatcher对象存放在类型为ArrayMap的mReceivers数据结构中。

ReceiverDispatcher,顾名思义,是一个广播分发器。从mReceivers数据结构就可以得出,通过MainActivity对象就可以找到ArrayMap,通过BroadcastReceiver对象就可以知道ReceiverDispatcher。

现在看下getReceiverDispatcher的返回值,它的类型是IIntentReceiver,通过ReceiverDispatcher的getIIntentReceiver方法获取。我们看下ReceiverDispatcher和getIIntentReceiver。

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;

}

...

final IIntentReceiver.Stub mIIntentReceiver;

...

ReceiverDispatcher(BroadcastReceiver receiver, Context context,

Handler activityThread, Instrumentation instrumentation,

boolean registered) {

if (activityThread == null) {

throw new NullPointerException("Handler must not be null");

}

mIIntentReceiver = new InnerReceiver(this, !registered);

mReceiver = receiver;

mContext = context;

mActivityThread = activityThread;

mInstrumentation = instrumentation;

mRegistered = registered;

mLocation = new IntentReceiverLeaked(null);

mLocation.fillInStackTrace();

}

...

BroadcastReceiver getIntentReceiver() {

return mReceiver;

}

IIntentReceiver getIIntentReceiver() {

return mIIntentReceiver;

}

...

}

由上可知,getIIntentReceiver返回mIIntentReceiver,它是InnerReceiver类的对象。InnerReceiver是ReceiverDispatcher的内部类,创建是在ReceiverDispatcher构造方法中,InnerReceiver继承自IIntentReceiver.Stub,它是一个Binder对象。InnerReceiver保存了外部类ReceiverDispatcher的对象。所以通过返回的InnerReceiver binder对象,就可以找到ReceiverDispatcher对象。如图所示:

mReceivers.png

现在返回registerReceiverInternal方法中。

try {

final Intent intent = ActivityManager.getService().registerReceiver(

mMainThread.getApplicationThread(), mBasePackageName, rd, filter,

broadcastPermission, userId, flags);

if (intent != null) {

intent.setExtrasClassLoader(getClassLoader());

intent.prepareToEnterProcess();

}

return intent;

} catch (RemoteException e) {

throw e.rethrowFromSystemServer();

}

registerReceiverInternal获取到IIntentReceiver binder对象之后,会通过ActivityManager调用registerReceiver,它是一个binder调用,它一共有7个参数:第一个参数是ApplicationThread binder对象,第二个参数是包名,第三个参数IIntentReceiver binder对象,第四个参数Intentfilter对象,第五个参数是广播权限,第六个参数是进程的userid,第七个参数是一个int类型的flag。

总结:

一个Context(Activity或者Service)可能会有多个BroadcastReceiver,多个BroadcastReceiver又一一对应多个ReceiverDispatcher,多个ReceiverDispatcher又一一对应多个IIntentReceiver。

mReceivers.png

你会发现在应用层并没有处理filter对象,而是当作参数传给了system_server进程。

system_server 部分

ActivityManager.getService().registerReceiver会调用到AMS的registerReceiver方法。

public Intent registerReceiver(IApplicationThread caller, String callerPackage,

IIntentReceiver receiver, IntentFilter filter, String permission, int userId,

int flags) {

...

ProcessRecord callerApp = null;

...

int callingUid;

int callingPid;

...

synchronized(this) {

// 1

if (caller != null) {

callerApp = getRecordForAppLocked(caller);

...

callingUid = callerApp.info.uid;

callingPid = callerApp.pid;

} else {

callerPackage = null;

callingUid = Binder.getCallingUid();

callingPid = Binder.getCallingPid();

}

...

// Collect stickies of users

...

}

...

// The first sticky in the list is returned directly back to the client.

...

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);

}

...

// 2

mRegisteredReceivers.put(receiver.asBinder(), rl);

}

...

BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,

permission, callingUid, userId, instantApp, visibleToInstantApps);

if (rl.containsFilter(filter)) {

Slog.w(TAG, "Receiver with filter " + filter

+ " already registered for pid " + rl.pid

+ ", callerPackage is " + callerPackage);

} else {

rl.add(bf);

...

// 3

mReceiverResolver.addFilter(bf);

}

// Enqueue broadcasts for all existing stickies that match

// this filter.

...

return sticky;

}

}

/**

* Keeps track of all IIntentReceivers that have been registered for broadcasts.

* Hash keys are the receiver IBinder, hash value is a ReceiverList.

*/

final HashMap mRegisteredReceivers = new HashMap<>();

/**

* Resolver for broadcast intents to registered receivers.

* Holds BroadcastFilter (subclass of IntentFilter).

*/

final IntentResolver mReceiverResolver

= new IntentResolver() {

...

};

ReceiverList(ActivityManagerService _owner, ProcessRecord _app,

int _pid, int _uid, int _userId, IIntentReceiver _receiver) {

owner = _owner;

receiver = _receiver;

app = _app;

pid = _pid;

uid = _uid;

userId = _userId;

}

BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,

String _packageName, String _requiredPermission, int _owningUid, int _userId,

boolean _instantApp, boolean _visibleToInstantApp) {

super(_filter);

receiverList = _receiverList;

packageName = _packageName;

requiredPermission = _requiredPermission;

owningUid = _owningUid;

owningUserId = _userId;

instantApp = _instantApp;

visibleToInstantApp = _visibleToInstantApp;

}

/**

* All filters that have been registered.

*/

private final ArraySet mFilters = new ArraySet();

AMS的registerReceiver主要分为三个部分,分别是代码1,代码2,代码3.

代码1:利用传递过来的ApplicationThread binder对象获取注册广播的应用的信息的存储变量callerApp,它的类型是ProcessRecord。在这里获取应用的uid和进程的pid。system_server如果注册的广播,会走到else部分,即callerPackage=null。

代码2:mRegisteredReceivers是一个以IIntentReceiver为key,以rl即ReceiverList列表为value的hashmap,IIntentReceiver不再多做解释,ReceiverList用来保存IIntentReceiver。

代码3:BroadcastFilter对象的目的是关联ReceiverList和IntentFilter。mReceiverResolver存储所有的BroadcastFilter到mFilters。

mRegisteredReceivers_mReceiverResolver.png

参考

忘了参考的哪里了,大部分自己看的。继续努力。

相关推荐

兔子多久下一窝?了解兔子繁殖周期与生育习性
365用英语怎么翻译

兔子多久下一窝?了解兔子繁殖周期与生育习性

⏳ 12-18 👁️ 1766
天龙八部如何刷马
365用英语怎么翻译

天龙八部如何刷马

⏳ 12-09 👁️ 3451