BroadcastReceiver 工作流程

本文主要通过源码介绍BroadcastReceiver的工作流程,主要包含两个方面:
一:BroadcastReceiver的注册过程;
二:BroadcastReceiver的发送与接受过程;

这里先回顾一下广播的的使用方法;

广播的接受:

public class BroadcastReceiverTest extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // onReceive 不能做耗时操作,参考值10s
    }
}

广播的注册:
广播的注册分为两种:静态注册,动态注册

静态注册:

        //广播接受者
        
   
            
   
                 //广播过滤器 name
                
   
            
        

动态注册:

//实例化过滤器
IntentFilter intentFilter = new IntentFilter();
//添加过滤的Action值;
intentFilter.addAction("com.xxx.BroadcastReceiver");
//将广播监听器和过滤器注册在一起
registerReceiver(new BroadcastReceiverTest(),intentFilter);

 //销毁Activity时取消注册广播监听器;
  unregisterReceiver(new BroadcastReceiverTest());

Intent intent = new Intent();
intent.setAction("com.xxx.BroadcastReceiver");
sendBroadcast(intent);

动态广播,静态广播差异点:

静态广播:在AndroidManifest.xml中定义,不需程序启动即可接收,可用作自动启动程序
动态广播:只能在代码中注册,程序适应系统变化做操作,程序运行状态才能接收到

下面我们对Broadcastreceiver 注册过程进行详细的分析;

广播中的静态注册是在应用安装时由系统自定完成注册,具体时由PackageManagerService 来完成注册,除了广播以外,其他三大组件也都是在应用安装时由PackageManagerService解析并注册的。我们这里值分析广播的动态注册过程。

 Context mBase;
@Override
    public Intent registerReceiver(
        BroadcastReceiver receiver, IntentFilter filter) {
        return mBase.registerReceiver(receiver, filter);
    }

在registerReceiver中我们通过源码可以看出 内部调用了mBase.registerReceiver 方法,而mBase 是Context 对象,
Context的实现类是 ContextImpl;

class ContextImpl extends Context{}

因此我们只需要看ContextImpl中的 registerReceiver 方法即可。

 @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext());
    }

通过源码我们可以看出 最终是 执行到 registerReceiverInternal 方法

   private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            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 {
            final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

通过源码可以看出 registerReceiverInternal 方法中通过 mPackageInfo 首先获取一个 IIntentReceiver 接口对象;

以下我们来具体分析一下 为什么通过mPackageInfo 获取一个IIntentReceiver 接口对象,而不是直接获取一个BroadcastReceiver 对象?

首先上述注册过程是一个跨进程通信的过程,而BroadcastReceiver 作为一个Android 的组件是不能直接跨进程传递的,所以通过IIntentReceiver来中转一下,通过源码 我们可以看到

public final class LoadedApk {
    private final ArrayMap
   
    > mReceivers = new ArrayMap
    
     >(); .... static final class ReceiverDispatcher { final static class InnerReceiver extends IIntentReceiver.Stub { } } } 
    
   

IIntentReceiver 的实现类是 LoadApk.ReceiverDispatcher.InnerReceiver.
而InnerReceiver 毫无疑问是一个Binder 接口,支持进程间的通信。
同时 LoadApk内部通过 ArrayMap 同时保存了BroadcastReceiver和ReceiverDispatcher 对象,这样当接受到广播时,ReceiverDispatcher 可以很方便的调用BroadcastReceiver的onReceiver方法。
具体的实现代码:

 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered){
    ...
       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); } ... }
   

接下来的代码中我们可以看到 执行了 ActivityManagerNative.getDefault().registerReceiver(…… rd….)
而ActivityManagerNative.getDefault()通过源码 我们可以看到

static public IActivityManager getDefault() {
        return gDefault.get();
    }
public abstract class ActivityManagerNative extends Binder implements IActivityManager{}
public final class ActivityManagerService extends ActivityManagerNative{}

由此可以看出 最终是执行到了 ActivityManagerService.registerReceiver(…..) 方法
下面我们只需要看registerReceiver 该方法内部是如何实现的。

 final IntentResolver
   
     mReceiverResolver = new IntentResolver
    
     (){} final HashMap
     
       mRegisteredReceivers = new HashMap<>(); public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { .... mRegisteredReceivers.put(receiver.asBinder(), rl); ..... mReceiverResolver.addFilter(bf); }
     
    
   

上述源码有点长,其实我们只需要关注上面的两行代码即可,而上面两行代码的作用就是将远程的InnerReceiver 对象以及 IntentFilter对象存储起来。 这样 整个广播的注册过程就完成了。

下面我们看一下广播的发送以及接受是如何实现的。

广播的发送是通过sendBroadcast 执行的,

  @Override
    public void sendBroadcast(Intent intent) {
        mBase.sendBroadcast(intent);
    }

通过源码我们可以看出,其实是执行到了 ContextImpl.sendBroadcast(….) 方法,紧接着我们只需要看 该方法是如何实现的即可。

  @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManagerNative.getDefault().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

该方法内部我们看到了 实际上是调用了 ActivityManagerService.broadcastIntent(….)


    public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean serialized, boolean sticky, int userId) {
        enforceNotIsolatedCaller("broadcastIntent");
        synchronized(this) {
            .....
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, userId);
           ....
            return res;
        }
    }

而改方法内部其实是直接调用了 broadcastIntentLocked 方法

final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {

         intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
        .....
         int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            // If we are not serializing this broadcast, then send the
            // registered receivers separately so they don't wait for the
            // components to be launched.
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(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);
            final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }
        ....
}

在broadcastIntentLocked 方法内部 首先是为Intent.addFlag(….) 表示默认情况下广播是不会发送给已经停止的应用。

注: FLAG_INCLUDE_STOPPED_PACKAGES :表示包含已经停止的应用,这个时候广播会发送给已经停止的应用
FLAG_EXCLUDE_STOPPED_PACKAGES:表示不包含已经停止的应用,这个时候广播不会发送给已经停止的应用。

紧接着我们看到 broadcastIntentLocked 内部会根据Intent-filter 查找出匹配的广播接受者 并将该接受者 添加到 BroadcastQueue中;

queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();

添加完成之后,紧接着调用了 scheduleBroadcastsLocked 方法,在该方法内部可以看到


    public void scheduleBroadcastsLocked() {
        ...
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

内部并没有立即发送广播 而是 发送了一条 BROADCAST_INTENT_MSG 的消息
而在Handler 中 我们可以看出

  @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                    processNextBroadcast(true);
                } bre

接受到 BROADCAST_INTENT_MSG 消息之后 调用了 processNextBroadcast 该方法。

  final ArrayList
   
     mParallelBroadcasts = new ArrayList<>() final void processNextBroadcast(boolean fromMsg){ .... while (mParallelBroadcasts.size() > 0) { r = mParallelBroadcasts.remove(0); r.dispatchTime = SystemClock.uptimeMillis(); r.dispatchClockTime = System.currentTimeMillis(); final int N = r.receivers.size(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast [" + mQueueName + "] " + r); for (int i=0; i
    
   

内部会遍历 mParallelBroadcasts 并将 其中的广播发送给对应的广播接受者,而发送是通过 deliverToRegisteredReceiverLocked 方法进行发送的。

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
    ....
     performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
    .....

}

内部调用到了 performReceiveLocked 方法来实现具体到发送过程。


    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
                     if (app != null) {
            if (app.thread != null) {
                // If we have an app thread, do the call through that so it is
                // correctly ordered with other one-way calls.
                try {
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
                // DeadObjectException when the process isn't actually dead.
                //} catch (DeadObjectException ex) {
                // Failed to call into the process.  It's dying so just let it die and move on.
                //    throw ex; 
                } catch (RemoteException ex) {
                    // Failed to call into the process. It's either dying or wedged. Kill it gently.
                    synchronized (mService) {
                        Slog.w(TAG, "Can't deliver broadcast to " + app.processName
                                + " (pid " + app.pid + "). Crashing it.");
                        app.scheduleCrash("can't deliver broadcast");
                    }
                    throw ex;
                }
            } else {
                // Application has died. Receiver doesn't exist.
                throw new RemoteException("app.thread must not be null");
            }
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }

可以看出来 内部调用了 ApplicationThreadNative.scheduleRegisteredReceiver 进行进程间的通信,之后 调用了 receiver.performReceive 方法

  public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            if (intent == null) {
                Log.wtf(TAG, "Null intent received");
            } else {
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                }
            }
            if (intent == null || !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);
                }
            }
        }

内部会创建一个Args 对象,并通过mActivityThread的post方法来执行 args中的逻辑
而Args我们可以看出

final class Args extends BroadcastReceiver.PendingResult implements Runnable{}

其实是一个实现了Runnable接口的对象,在run方法内我们可以看到最终调用到了

  try {
                    ClassLoader cl =  mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    intent.prepareToEnterProcess();
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {

很显然 BroadcastReceiver 中的 onReceiver方法被执行了,也就是说应用已经接受到广播了,同时onReceiver方法是在广播接受者的主线程中被调用了。至此 广播的注册、发送、接受已经分析完成了。

总结:
广播的注册过程 :最终在ActivityManagerService中将远程的InnerInnerReceiver以及Intent-filter对象存储起来。
广播的发送以及接受:内部会首先根据传入的Intent-filter 查找出匹配的广播接受者,并将改接受者放到BroadcastQueue中,紧接着系统会遍历ArrayList中的广播,并将其发送给它们对应的广播接受者,最后调用到广播接受者的onReceiver方法。

大致流程图:

《BroadcastReceiver 工作流程》

    原文作者:PackageManagerService
    原文地址: https://juejin.im/entry/5821899dbf22ec0068e27cf8
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞