Android 7.0 ActivityManagerService(5) 广播(Broadcast)相关流程分析(1) 联系客服

发布时间 : 星期一 文章Android 7.0 ActivityManagerService(5) 广播(Broadcast)相关流程分析(1)更新完毕开始阅读

//broadcastPermission与静态注册中的permission标签对应,用于对广播发送方的权限进行限制

//只有拥有对应权限的发送方,发送的广播才能被此receiver接收

//不指定scheduler时,receiver收到广播后,将在主线程调用onReceive函数 //指定scheduler后,onReceive函数由scheduler对应线程处理

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {

//ContextImpl是Context家族中实际工作的对象,getOuterContext得到的是ContextImpl对外的代理

//一般为Application、Activity、Service等

return registerReceiverInternal(receiver, getUserId(),

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

与上述代码类似,不论调用Context中的哪个接口注册BroadcastReceiver,最终流程均会进入到registerReceiverInternal函数。

现在,我们跟进一下registerReceiverInternal函数:

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) { IIntentReceiver rd = null;

if (receiver != null) {

//mPackageInfo的类型为LoadedApk

if (mPackageInfo != null && context != null) { if (scheduler == null) {

//未设置scheduler时,将使用主线程的handler处理

//这就是默认情况下,Receiver的onReceive函数在主线程被调用的原因 scheduler = mMainThread.getHandler(); }

//getReceiverDispatcher函数的内部,利用BroadcastReceiver构造出ReceiverDispatcher

//返回ReceiverDispatcher中的IIntentReceiver对象

//IIntentReceiver是注册到AMS中,供AMS回调的Binder通信接口 rd = mPackageInfo.getReceiverDispatcher( receiver, context, scheduler,

mMainThread.getInstrumentation(), true); } else {

//这段代码写的我瞬间懵逼了。。。scheduler == null对应的判断,明显可以移出

if-else结构的

//不符合大google的逼格 if (scheduler == null) {

scheduler = mMainThread.getHandler(); }

//主动创建

rd = new LoadedApk.ReceiverDispatcher(

receiver, context, scheduler, null, true).getIIntentReceiver(); } }

try {

//将Receiver注册到AMS

final Intent intent = ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId); .................

} catch (RemoteException e) { ........... } }

以上代码中主要的工作是:

创建BroadcastReceiver对应的ReceiverDispatcher,得到ReceiverDispatcher内部的IIntentReceiver对象,

然后利用Binder通信将该对象连同BroadcastReceiver的其它信息注册到AMS中。

IIntentReceiver对应的继承关系如下图所示:

结合上图,我们需要知道的是:

1、BroadcastReceiver收到的广播实际上是AMS发送的,因此BroadcastReceiver与AMS之间必须进行Binder通信。

从类图可以看出,BroadcastReceiver及其内部成员并没有直接继承Binder类。

负责与AMS通信的,实际上是定义于LoadedApk中的InnerReceiver类,该类继承IIntentReceiver.Stub,作为Binder通信的服务端。

从上文的代码可以看出,注册BroadcastReceiver时,会将该对象注册到AMS中供其回调。

当InnerReceiver收到AMS的通知后,将会调用ReceiverDispatcher进行处理。

由于ReceiverDispatcher持有了实际的BroadcastReceiver,于是最终将广播递交给BroadcastReceiver的onReceive函数进行处理。

以上的设计思路实际上是:

将业务接口(处理广播的BroadcastReceiver类)与通信接口(InnerReceiver类)分离,由统一的管理类(ReceiverDispatcher)进行衔接。

这基本是Java层使用Binder通信的标配,AIDL本身也是这种思路。

2、BroadcastRecevier中定义了一个PendingResult类,该类用于异步处理广播消息。

从上文的代码我们知道了,如果没有明确指定BroadcastReceiver对应的handler,那么其onReceive函数将在主线程中被调用。

因此当onReceive中需要执行较耗时的操作时,会阻塞主线程,影响用户体验。 为了解决这种问题,可以在onReceive函数中采用异步的方式处理广播消息。

一提到异步的方式处理广播消息,大家可能会想到在BroadcastReceiver的onReceive中单独创建线程来处理广播消息。 然而,这样做存在一些问题。

例如:

对于一个静态注册的BroadcastReceiver 对象,对应的进程初始时可能并没有启动。 当AMS向这个BroadcastReceiver对象发送广播时,才会先启动对应的进程。

一旦BroadcastReceiver对象处理完广播,i并将返回结果通知给AMS后,AMS就有可能清理掉对应进程。

因此,若在onReceive中创建线程处理问题,那么onReceive函数就可能在线程完成工作前返回,导致AMS提前销毁进程。

此时,线程也会消亡,使得工作并没有有效完成。

为了解决这个问题,就可以用到BroadcastReceiver提供的PendingResult。 具体的做法是:

先调用BroadcastReceiver的goAsync函数得到一个PendingResult对象, 然后将该对象放到工作线程中去释放。

这样onReceive函数就可以立即返回而不至于阻塞主线程。

同时,Android系统将保证BroadcastReceiver对应进程的生命周期, 直到工作线程处理完广播消息后,调用PendingResult的finish函数为止。

其中原理是:

正常情况下,BroadcastReceiver在onReceive函数结束后,

判断PendingResult不为null,才会将处理完毕的信息通知给AMS。

一旦调用BroadcastReceiver的goAsync函数,就会将BroadcastReceiver中的PendingResult置为null,

因此即使onReceive函数返回,也不会将信息通知给AMS。 AMS也就不会处理BroadcastReceiver对应的进程。

待工作线程调用PendingResult的finish函数时,才会将处理完毕的信息通知给AMS。

代码示例如下:

private class MyBroadcastReceiver extends BroadcastReceiver { ..................

public void onReceive(final Context context, final Intent intent) { //得到PendingResult

final PendingResult result = goAsync();

//放到异步线程中执行

AsyncHandler.post(new Runnable() { @Override

public void run() {

handleIntent(context, intent);//可进行一些耗时操作 result.finish(); } }); } }

final class AsyncHandler {

private static final HandlerThread sHandlerThread = new HandlerThread(\ private static final Handler sHandler;

static {

sHandlerThread.start();

sHandler = new Handler(sHandlerThread.getLooper()); }

public static void post(Runnable r) { sHandler.post(r); }

private AsyncHandler() {} }