BroadcastReciver 工作原理

333 阅读5分钟

通过这篇文章,我们来梳理一下 BroadcastReceiver 的工作原理以及其中我们应该注意的细节

BroadcastReceiver 注册整体流程

BroadcastReceiver 的注册分为静态注册和动态注册

由于 Goolge 规定在 Android 7.0 以上的系统中不能静态注册 BroadcastReciver了 (即使你静态注册了 BroadcastReciver,该 BroadcastReciver 也不会运行)

对于我们开发者而言,可以直接忽略 BroadcastReceiver 的静态注册了

因此本篇博客只分析 BroadcastReceiver 动态注册流程

总体流程如下图:

流程其实很简单,就是将 BroadcastReciver 的相关信息保存到 AMS 中就完成动态注册了

Broadcast 发送整体流程

Broadcast 有几种类型:无序广播、有序广播和粘性广播,三者相比各自具有不同的特性,但它们的发送流程是类似的

为了方便理清整体流程,因此本篇博客只分析最简单的无序广播的发送流程

总体流程如下图:

这里我默认 BroadcastReciver 是通过动态注册的,因此 BroadcastReciver 运行在 UI 主线程中 (动态注册的 BroadcastReciver 都是运行在 UI 主线程中)

Broadcast 的发送主要由 AMS 管理,AMS 会将所要发送的 Broadcast 信息与所有已注册的 BroadcastReciver 信息 (权限 + IntentFilter) 进行比对,将广播发送给满足条件的 BroadcastReciver

由于 BroadcastReciver 运行在其他进程中,AMS 需要 AIDL 调用 BroadcastReciver 运行所在进程,传递 intent 等信息,并最终调用 BroadcastReceiver 的 onReceive() 函数

源码

BroadcastReceiver 注册流程

ContextImpl.registerReceiver()

// frameworks/base/core/java/android/app/ContextImpl.java
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
{
    return registerReceiver(receiver, filter, null, null);
}

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

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, // scheduler = null
            Context context
){
    IIntentReceiver rd = null;
    // if 命中
    if (receiver != null)
    {
        // APK 包信息不为空 且 上下文也不为空,if 命中
        if (mPackageInfo != null && context != null)
        {
            if (scheduler == null)
            {
                scheduler = mMainThread.getHandler();
            }
            // 调用 LoadedApk 的 getReceiverDispatcher 函数,
            // 从 mReceivers 缓存中获取 BroadcastReceiver 的 Binder 通信接口
            rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
        }
        else
        {
            ......
        }
    }

    // AIDL 调用 ActivityManagerService 的 registerReceiver 函数
    return ActivityManagerNative.getDefault().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName,
                rd, filter, broadcastPermission, userId);
}

所有可用 (已注册的) 的 BroadcastReceiver 信息都保存在 mReceivers 缓存中

mReceivers 是一个 ArrayMap,以 Context 为 key,以 ReceiverDispatcher 为 value

可以把 ReceiverDispatcher 理解为是一个对于 BroadcastReceiver 及其 Binder 通信接口的封装类

ActivityManagerService.registerReceiver()

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, 
			String permission, int userId
){
    ......

    synchronized (this)
    {
        ......

        // 判断该 BroadcastReceiver 是否已经注册
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        // rl = null,表示该 BroadcastReceiver 还没有注册
        if (rl == null)
        {
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);

            ......

            // 将该 BroadcastReceiver 的 Binder 通信接口缓存
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        }
        
        ......

        // 创建该 BroadcastReceiver 的 IntentFilter 对象
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId);
        rl.add(bf);

        // 将该 IntentFilter 对象缓存
        mReceiverResolver.addFilter(bf);

        ......
    }
}

Broadcast 发送流程

ContextImpl.sendBroadcast()

// frameworks/base/core/java/android/app/ContextImpl.java
public void sendBroadcast(Intent intent)
{
    ......
    
    // AIDL 调用 ActivityManagerService 的 broadcastIntent 函数
    ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null, 
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, 
        	false, false, getUserId());
    
    ......
}

ActivityManagerService.broadcastIntent()

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle options,
            boolean serialized, boolean sticky, int userId
){
    synchronized(this)
    {
        // 验证 intent 是否合法
        intent = verifyBroadcastLocked(intent);
        
        ......

        int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, null, serialized, sticky,
                    callingPid, callingUid, userId);
        
        ......
        
        return res;
    }
}

ActivityManagerService.verifyBroadcastLocked()

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final Intent verifyBroadcastLocked(Intent intent)
{
    // 如果 intent 含有文件描述符,则抛出异常,防止出现泄漏
    if (intent != null && intent.hasFileDescriptors() == true)
    {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }

    int flags = intent.getFlags();

    // 如果 APP 进程正在启动中
    if (!mProcessesReady)
    {
        // 如果 flag 设置了 FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
        // (APP 启动检查时只接受动态注册的 BroadcastReceiver)
        if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0)
        {
            
        }
        // 如果 flag 没有设置 FLAG_RECEIVER_REGISTERED_ONLY,则抛出异常
        // (只接受动态注册的 BroadcastReceiver)
        else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0)
        {
            throw new IllegalStateException("Cannot broadcast before boot completed");
        }
    }

    if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0)
    {
        throw new IllegalArgumentException("Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
    }

    return intent;
}

ActivityManagerService.broadcastIntentLocked()

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, 
            Bundle options, boolean ordered, boolean sticky, int callingPid, 
            int callingUid, int userId
){
    intent = new Intent(intent);
    
    // 添加 FLAG_EXCLUDE_STOPPED_PACKAGES 标志 (广播不会发送给已经停止的 APP 应用)
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
    
    // 将动态注册的 BroadcastReceiver 和静态注册的 BroadcastReceiver 
    // 按照优先级高低缓存在不同的集合中,再将这两个集合合并到 receivers 集合中
    // 其中的代码细节与主流程无关,有兴趣可以自行了解
    ......

    // receivers 集合包含所有已注册的 BroadcastReceiver,if 命中
    if ((receivers != null && receivers.size() > 0) || resultTo != null)
    {
        // 获取 BroadcastQueue
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        // 创建 BroadcastRecord 并传入 receivers 进行记录
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, resolvedType,
                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                    resultData, resultExtras, ordered, sticky, false, userId);

        ......

        queue.scheduleBroadcastsLocked();
    }

    return ActivityManager.BROADCAST_SUCCESS;
}

BroadcastQueue.scheduleBroadcastsLocked()

// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
public void scheduleBroadcastsLocked()
{
    ......

    // 发送消息 (BROADCAST_INTENT_MSG) 给 BroadcastQueue 中的内部类 BroadcastHandler (Handler)
    // 从 Binder 线程切换到主线程执行
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;

    ......
}

BroadcastHandler.handleMessage()

// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue$BroadcastHandler.java
public void handleMessage(Message msg)
{
    switch (msg.what)
    {
        case BROADCAST_INTENT_MSG: {
            ......
            processNextBroadcast(true);
        } break;

        ......
    }
}

BroadcastQueue.processNextBroadcast()

// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg)
{
    synchronized(mService)
    {
        BroadcastRecord r;

        ......

        // fromMsg = true,if 命中
        if (fromMsg)
        {
            // 由于 BroadcastHandler 使用的是主线程传递消息,消息可能会延迟
            // mBroadcastsScheduled 用于表示 BROADCAST_INTENT_MSG 已被处理
            mBroadcastsScheduled = false;
        }

        // mParallelBroadcasts 集合用于存储无序广播,遍历 mParallelBroadcasts
        while (mParallelBroadcasts.size() > 0)
        {
            // 取出 mParallelBroadcasts 集合中的首部
            r = mParallelBroadcasts.remove(0);
            r.dispatchTime = SystemClock.uptimeMillis();
            r.dispatchClockTime = System.currentTimeMillis();

            // 遍历所有已注册的 BroadcastReceiver
            final int N = r.receivers.size();
            for (int i=0; i<N; i++)
            {
                // 获取 BroadcastReceiver
                Object target = r.receivers.get(i);
                // 将无序广播发送给 BroadcastReceiver
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
            }

            ......
        }

        // 将有序广播发送给对应的 BroadcastReceiver
    	// 其中的代码细节与本次流程无关,有兴趣可以自行了解
        ......
    }
}

BroadcastQueue.deliverToRegisteredReceiverLocked()

// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered
){
    boolean skip = false;

    // 检查该 BroadcastReceiver 是否拥有权限
    // 其中的代码细节与主流程无关,有兴趣可以自行了解
    ......

    // 如果该 BroadcastReceiver 拥有权限,则 skip = false
    if (!skip)
    {
        ......
            
        performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                    new Intent(r.intent), r.resultCode, r.resultData,
                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
        
        ......
    }
}

BroadcastQueue.performReceiveLocked()

// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser
){
    // 如果 app 不为空,表示该 BroadcastReceiver 运行所在进程存在
    if (app != null)
    {
        // 如果 app.thread 不为空,表示该 BroadcastReceiver 运行所在进程正在运行中
        if (app.thread != null)
        {
            // AIDL 调用该 BroadcastReceiver 运行所在进程 
            // ApplicationThread 的 scheduleRegisteredReceiver 函数
            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser, app.repProcState);
        }
        else // 如果该 BroadcastReceiver 运行所在进程未启动 / 该 BroadcastReceiver 不存在,
             // 则抛出异常
        {
            throw new RemoteException("app.thread must not be null");
        }
    }
    else
    {
        ......
    }
}

ApplicationThread.scheduleRegisteredReceiver()

// frameworks/base/core/java/android/app/ActivityThread.java
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
		int resultCode, String dataStr, Bundle extras, boolean ordered,
		boolean sticky, int sendingUser, int processState
){
    updateProcessState(processState, false);
    // 调用该 BroadcastReceiver 的 Binder 通信接口的 performReceive 函数
    receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                sticky, sendingUser);
}

InnerReceiver.performReceive()

// frameworks/base/core/java/android/app/LoadedApk$ReceiverDispatcher$InnerReceiver.java
public void performReceive(Intent intent, int resultCode, String data,
		Bundle extras, boolean ordered, boolean sticky, int sendingUser
){
    // 获取 ReceiverDispatcher (弱引用,防止内存泄漏)
    LoadedApk.ReceiverDispatcher rd = mDispatcher.get();

    ......

    if (rd != null)
    {
        rd.performReceive(intent, resultCode, data, extras,
                    ordered, sticky, sendingUser);
    }

    ......
}

ReceiverDispatcher.performReceive()

// frameworks/base/core/java/android/app/LoadedApk$ReceiverDispatcher.java
public void performReceive(Intent intent, int resultCode, String data,
		Bundle extras, boolean ordered, boolean sticky, int sendingUser
){
    ......

    // 将广播的 intent 等相关信息封装为 Args (本质上是 Runnable)
    Args args = new Args(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    // 发送消息给 ActivityThread 中的内部类 H (Handler)
    if (!mActivityThread.post(args))
    {
        ......
    }
}

Args.run()

// frameworks/base/core/java/android/app/LoadedApk$ReceiverDispatcher$Args.java
public void run()
{
    ......

    // 通过反射创建该 BroadcastReceiver
    ClassLoader cl =  mReceiver.getClass().getClassLoader();
    intent.setExtrasClassLoader(cl);
    setExtrasClassLoader(cl);
    receiver.setPendingResult(this);
    // 回调该 BroadcastReceiver 的 onReceive 函数,传入 intent
    receiver.onReceive(mContext, intent);

    ......
}

总结

本篇文章分析了 BroadcastReceiver 的注册流程和 Broadcast 的发送流程,将其中对于我们开发者而言比较有意义的部分代码进行了分析

由于 BroadcastReceiver 分为静态注册和动态注册,Broadcast 又分为无序广播、有序广播和粘性广播等多种类型,需要多情况讨论,一篇博客显然是无法将其全部分析完的

希望读者能够参照本篇文章尝试自己去阅读源码,加深理解