Android开发程序员

你想知道的BroadcastReceiver工作原理

2018-03-22  本文已影响407人  Jesse_zhao

一、概要

BoradcastReceiver在Android中充当的是传递数据和消息的作用。尽管现在有很多框架(比如EventBus、Rxjava等)可以代替它在应用内传递消息和数据,但是不同的是BoradcastReceiver可以跨进新传递数据。所以了解BoradcastReceiver的实现还是比较重要的。这里分析广播机制注意围绕三个方法进行:registerReceiver()、sendBroadcast()和unregisterReceiver()。如果你只是想了解它的使用的话,可以参考下这篇文章Android广播机制总结

1、涉及主要类

android.app.ContextImpl.java 
android.app.Instrumentation.java 
android.app.ActivityThread.java
android.app.ActivityManager.java
com.android.server.am.ActivityManagerService.java
android.content.BroadcastReceiver.java
com.android.server.am.BroadcastQueue.java
com.android.server.am.BroadcastRecord.java
android.app.LoadedApk.java

2、流程图


BroadcastReceiver流程.png 3、简要图 BroadcastReceiver运作简单示意图.png

从这里我们可以看出这个广播机制运用的是发布/订阅者模式来设计的。

二、具体流程

1.1、ContextImpl.registerReceiver()

这里最终会调用registerReceiverInternal()方法:

  private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
        IntentFilter filter, String broadcastPermission,
        Handler scheduler, Context context, int flags) {
    IIntentReceiver rd = null;
    if (receiver != null) {
    //这里先获取ActivityThread.java中的H实例
        if (mLoadedApk != null && context != null) {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = mLoadedApk.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 {
    //使用Binder IPC机制和AMS进行通信
        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();
    }
}           

这里主要就是创建了LoadApk.ReceiverDispatcher的实例,这个实例用于传播广播用的。然后接下来我们看下AMS中的registerReceiver方法:

1.2、ActivityManageService.registerReceiver()
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
        int flags) {
   // 省略部分代码
    // 这里处理Sticky广播
    ...
    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);
            } else {
                try {
                    receiver.asBinder().linkToDeath(rl, 0);
                } catch (RemoteException e) {
                    return sticky;
                }
                rl.linkedToDeath = true;
            }
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        }
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId, instantApp, visibleToInstantApps);
        rl.add(bf);
        if (!bf.debugCheck()) {
            Slog.w(TAG, "==> For Dynamic broadcast");
        }
        //添加到Receiver集合中
        mReceiverResolver.addFilter(bf);
        // Enqueue broadcasts for all existing stickies that match
        // this filter.
        //处理Sticky广播,遍历保存的Sticky广播中有满足注册的received,直接发送
        if (allSticky != null) {
            ArrayList receivers = new ArrayList();
            receivers.add(bf);
            final int stickyCount = allSticky.size();
            for (int i = 0; i < stickyCount; i++) {
                Intent intent = allSticky.get(i);
                BroadcastQueue queue = broadcastQueueForIntent(intent);
                BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                        null, -1, -1, false, null, null, AppOpsManager.OP_NONE, null, receivers,
                        null, 0, null, null, false, true, true, -1);
                 //将记录着BroadcastRecevied信息的BroadcastRecord加入到BroadcastQueue中
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }
        return sticky;
    }
}

这里的主要逻辑是先收集用户发送的sticky广播,根据注册的received设置的IntentFilter去匹配相应的sticky广播。接着把注册的BroadcastFilter加入到mReceiverResolver的集合当中,同时也把记录着BroadcastRecevied信息的BroadcastRecord加入到BroadcastQueue中。最后一步就是如果received注册的IntentFilter有对应的sticky广播时,立即将对应的sticky广播发送给接收器,从这里可以看出sticky广播的机制(即注册时,若有相应的粘性广播相匹配时,会立即收到该广播)。

2.1、ContextImpl.sendBroadcast()
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().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();
    }
}

发送广播时,同样用到的是binder IPC机制与AMS进行通信。接着来看下AMS中的broadcastIntent()方法。

2.2、ActivityManageService.broadcastIntent()

最终会调用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) {
// 省略部分代码(检测权限及处理一些特别的广播)
    // Add to the sticky list if requested.
    if (sticky) {
        ...
        // 如果是粘性广播时,检查相应的权限
    }

    //找出已注册并满足条件的接收器 
    List receivers = null;
    List<BroadcastFilter> registeredReceivers = null;
    // Need to resolve the intent to interested receivers...
    if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
             == 0) {
        receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
    }
    if (intent.getComponent() == null) {
        if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
            // Query one target user at a time, excluding shell-restricted users
            for (int i = 0; i < users.length; i++) {
                if (mUserController.hasUserRestriction(
                        UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                    continue;
                }
                List<BroadcastFilter> registeredReceiversForUser =
                        mReceiverResolver.queryIntent(intent,
                                resolvedType, false /*defaultOnly*/, users[i]);
                if (registeredReceivers == null) {
                    registeredReceivers = registeredReceiversForUser;
                } else if (registeredReceiversForUser != null) {
                    registeredReceivers.addAll(registeredReceiversForUser);
                }
            }
        } else {
            //从mReceiverResolve找出相应的接收器
            registeredReceivers = mReceiverResolver.queryIntent(intent,
                    resolvedType, false /*defaultOnly*/, userId);
        }
    }

    final boolean replacePending =
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
            + " replacePending=" + replacePending);

    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
    //处理正常广播
    if (!ordered && NR > 0) {
        if (isCallerSystem) {
            checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                    isProtectedBroadcast, registeredReceivers);
        }
        final BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, callerInstantApp, 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) != null);
        // Note: We assume resultTo is null for non-ordered broadcasts.
        if (!replaced) {
            queue.enqueueParallelBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
        }
        registeredReceivers = null;
        NR = 0;
    }
    // Merge into one list.
    int ir = 0;
    //处理有序广播,广播接收器按照设置的priority进行排序
    //省略部分代码
    return ActivityManager.BROADCAST_SUCCESS;
}

这个方法比较长,对粘性广播、系统广播、有序广播和正常广播分别进行了处理,最终会匹配相应的注册了的广播接收器。最后执行BroadcastQueue的scheduleBroadcastsLocked()方法,也就是发送广播给接收器。

2.3、BroadcastQueue.scheduleBroadcastsLocked()

最终会执行performReceiveLocked()方法:

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
        Intent intent, int resultCode, String data, Bundle extras,
        boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
    // Send the intent to the receiver asynchronously using one-way binder calls.
    if (app != null) {
        if (app.thread != null) {
            try {
            //调用ActivityThread.scheduleRegisteredReceiver()方法
                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser, app.repProcState);
                           } catch (RemoteException ex) {
                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);
    }
}

这里的app.thread其实就是ActivityThread,我们再看ActivityThread. scheduleRegisteredReceiver方法:

 public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
            int resultCode, String dataStr, Bundle extras, boolean ordered,
            boolean sticky, int sendingUser, int processState) throws RemoteException {
        updateProcessState(processState, false);
        receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                sticky, sendingUser);
    }

这里的receiver就是之前在注册广播时获取的(见1.1)LoadApk.ReceiverDispatcher.InnerReceiver(Binder接口 IPC过程)然后再通过LoadApk.ReceiverDispatcher.performReceive()方法通过handle post出一个Runnable:

2.4、LoadApk.ReceiverDispatcher.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 || !mActivityThread.post(args.getRunnable())) {
            if (mRegistered && ordered) {
                IActivityManager mgr = ActivityManager.getService();
                if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                        "Finishing sync broadcast to " + mReceiver);
                args.sendFinished(mgr);
            }
        }
    }

这里通过ActivityThread.H的handler对象post了一个线程,我们看下这个线程的实现的主要代码:

public final Runnable getRunnable() {
            return () -> {
                final BroadcastReceiver receiver = mReceiver;
                final boolean ordered = mOrdered;
                //省略部分代码
                    ClassLoader cl = mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    intent.prepareToEnterProcess();
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    receiver.onReceive(mContext, intent);  

                //省略部分代码
            };
        }
    }

最终是通过ActivityThread.H对象post出一个线程,将 receiver.onReceive(mContext, intent); 方法的调用回到了主线程。

3、ContextImpl.unregisterReceiver()

取消接收器的注册也是通过AMS将receiver移除容器

void removeReceiverLocked(ReceiverList rl) {
    mRegisteredReceivers.remove(rl.receiver.asBinder());
    for (int i = rl.size() - 1; i >= 0; i--) {
        mReceiverResolver.removeFilter(rl.get(i));
    }
}

三、总结

简单点来说,注册一个接收器的时候会判断有没有粘性广播想匹配,有的话立即发送广播,同时将接收器放入相应的容器A中;当发送一个广播时,会从A中匹配出相应的接收器,然后在将广播挨个发送给接收器。

上一篇下一篇

猜你喜欢

热点阅读