广播动态注册过程分析

我们动态注册一个广播,一般是这么写:

BroadcastReceiver receiver=..;

IntentFilter filter=...;

MainActivity.this.registerReceiver(receiver,filter);

 

registerReceiver()具体实现在ContextImpl类中:

ContextImpl.java

#1

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {

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

}

 

#2

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,

String broadcastPermission, Handler scheduler) {

return registerReceiverInternal(receiver, filter, broadcastPermission,

scheduler, getOuterContext());

}

 

#3

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 {

if (scheduler == null) {

scheduler = mMainThread.getHandler();

}

rd = new LoadedApk.ReceiverDispatcher(

receiver, context, scheduler, null, true).getIIntentReceiver(); //关键点别漏了哦

}

}

try { //上面代码构建了一个rd,并保存。

广播动态注册过程分析

 

return ActivityManagerNative.getDefault().registerReceiver(

mMainThread.getApplicationThread(),

rd, filter, broadcastPermission); //filter实现了Parcelable接口

} catch (RemoteException e) {

return null;

}

}

上面干了些啥?

创建一个ReceiverDispatcher,获取内部的InnerReceiver,作为参数通过binder调用ams的注册方法

 

下面看看AMS.registerReceiver()方法:

AMS.java   p9977

 

public Intent registerReceiver(IApplicationThread caller,

IIntentReceiver receiver, IntentFilter filter, String permission)

{

synchronized(this) {

ProcessRecord callerApp = null;

if (caller != null) {                                     //根据传入的caller找到ProcessRecord

callerApp = getRecordForAppLocked(caller);

if (callerApp == null) {

throw new SecurityException(

"Unable to find app for caller " + caller

+ " (pid=" + Binder.getCallingPid()

+ ") when registering receiver " + receiver);

}

}

 

List allSticky = null;

 

// Look for any matching sticky broadcasts...

Iterator actions = filter.actionsIterator();                               //IntentFilter上设置的action们

if (actions != null) {

while (actions.hasNext()) {

String action = (String)actions.next();

allSticky = getStickiesLocked(action, filter, allSticky);

}

} else {

allSticky = getStickiesLocked(null, filter, allSticky);

}

 

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

// the client.

Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;

 

if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter

+ ": " + sticky);

 

if (receiver == null) {

return sticky;

}

 

ReceiverList rl                                            //根据binder key找到ReceiverList value

= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); //IIntentReceiver 类型

广播动态注册过程分析

 

if (rl == null) {

rl = new ReceiverList(this, callerApp,

Binder.getCallingPid(),

Binder.getCallingUid(), receiver);                                //IIntentReceiver 类型,实现了binder哦

if (rl.app != null) {                                           //app即为callerApp ,ProcessRecord 记录一个进程?

rl.app.receivers.add(rl);                                 //rl间接保存在ProcessRecord里面

} else {

try {

receiver.asBinder().linkToDeath(rl, 0);

} catch (RemoteException e) {

return sticky;

}

rl.linkedToDeath = true;

}

mRegisteredReceivers.put(receiver.asBinder(), rl);                            //rl保存在ams里,key为binder

}

BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);

rl.add(bf);

if (!bf.debugCheck()) {

Slog.w(TAG, "==> For Dynamic broadast");

}

mReceiverResolver.addFilter(bf);

 

// Enqueue broadcasts for all existing stickies that match

                                  // this filter. 这里和粘性广播有关,略过吧,分析主线即可

if (allSticky != null) {

ArrayList receivers = new ArrayList();

receivers.add(bf);

 

int N = allSticky.size();

for (int i=0; i<N; i++) {

Intent intent = (Intent)allSticky.get(i);

BroadcastRecord r = new BroadcastRecord(intent, null,

null, -1, -1, null, receivers, null, 0, null, null,

false, true, true);

if (mParallelBroadcasts.size() == 0) {

scheduleBroadcastsLocked();

}

mParallelBroadcasts.add(r);

}

}

 

return sticky;

}

}

上面这段代码干了以下这些事:

 

构建一个ReceiverList ,里面有对应于应用进程的ProcessRecord类型的callerApp,IItentReceiver类型的receiver(实现了binder,来自binder另一端)

 

然后,app.receivers.add(rl),也就是callerApp间接持有上面创建的rl,换种说法,ProcessRecord间接持有一个BroadcastFilter 类型的List列表

 

同时, mRegisteredReceivers.put(receiver.asBinder(), rl),rl保存在ams里,rl是List的子类哦

 

另外,创建一个BroadcastFilter ,里面有filter, rl, permission,并且, rl.add(bf),这里说明一下,ReceiverList 继承了ArrayLists,泛型参数是BroadcastFilter

 

最后, mReceiverResolver.addFilter(bf);暂时不明白上面意思。

上面只分析了典型的动态注册广播的过程,主要是为了让我们对广播的注册过程有个整体上的认识,至于细节部分,没必要都搞清楚,否则很容易走偏主线,打乱思路,不利分析,毕竟源码分析本竟是一个很枯燥的过程,

ps:这篇文章一开始是写在有道云笔记上的,所以没有怎么排版,而且我在对照源码分析时可能会删掉些无关紧要的代码,所以大家在分析时一定要自己对照源码,只有自己对照源码,自己尝试分析,才能真正的理解,进步,这个我深有体会。好的,这篇文章虽然写的不是很好,看还是希望对大家有帮助!!本人的写作水平实在不敢恭维,尤其是技术文章,见笑了,不过我会慢慢学习,加强写作和表达能力的。另外,文章可能有理解错误的地方,请谅解。。