理解四大组件Broadcast 发送与接收流程(基于Android10)

1,844 阅读22分钟

一、概述

广播作为Android四大组件之一,可以用来在进程/线程间通信。 应用注册特定的广播。广播发出后,系统会自动将广播发送给同意接收该广播的应用。

想要收到广播,首先就应该声明一个广播接收者,同时注册到系统中。 然后,程序发送能够匹配该注册广播的intent,由系统来匹配到,然后回调到注册者。

广播分为注册和发送两个部分。

1.1 广播注册

分为静态注册和动态注册:

  • 静态注册

通过在清单文件中声明。系统在apk安装时自动注册广播到系统中。注意:如果静态声明了广播接收器,系统会在广播发出时拉起应用(如果应用尚未启动)。

当然,在Android8.0后,应用不会收到隐式广播(不是指定发送给当前进程,如系统广播),避免瞬间拉起大量应用。当然也会有一些特例,如系统第一次启动广播、语言、时间发送变更等广播。

  • 动态注册

通过上下文context注册。只有上下问有效,才会收到广播。比如,使用activity的上下文,只有当activity未被销毁时,才能接收广播。 如果使用全局上下文,则在应用运行期间都会收到广播。

因此,如果在activity中注册广播,则需要在activity销毁时候,注销广播。否则会引起activity内存泄漏。

1.2 广播发送

  • 发送并行广播 sendBroadcast(Intent)

按随机的顺序向所有接收器发送广播,也称为常规广播,比串行广播高效。此时,广播不会被中断,不会被传递。

  • 发送串行广播 sendOrderedBroadcast(Intent, String)

一次发送一个广播到接收器。 当接收器逐个顺序执行时,接收器可以中止广播向下传递。

  • 发送本应用广播 LocalBroadcastManager.sendBroadcast 发送和接收在同一个进程中,这种方式高效,且不会被其他应用接收,安全性好。

1.3 广播对进程的影响

另外,当onReceive()方法在执行的时候,被系统认为是前台进程,存活优先级高。系统不会主动回收该进程,除非内存严重不足。当执onReceive()行完毕返回后,则会被当做普通进程,可能会被系统回收。

1.4 不同Android版本的广播变更

  • Android 7.0(24)及更高版本为目标平台:

应用必须使用 registerReceiver(BroadcastReceiver, IntentFilter) 注册 CONNECTIVITY_ACTION 广播。无法在清单中声明接收器。

  • Android 8.0(26)及更高版本为目标平台:

对于大多数隐式广播(没有明确针对您的应用的广播),您不能使用清单来声明接收器,只能通过上下文的方式动态注册。

  • Android 9.0(28)及更高版本为目标平台:

NETWORK_STATE_CHANGED_ACTION 广播不再接收有关用户位置或个人身份数据的信息。则通过 WLAN 接收的系统广播不包含 SSID、BSSID、连接信息或扫描结果。要获取这些信息,请调用 getConnectionInfo()

二、广播简单使用

2.1 静态注册

  1. 在清单文件中注册
<receiver
    android:name=".broadcast.MyStaticBroadcastReceiver"
    android:exported="true">
    <intent-filter>
         <action android:name="com.example.broadcast.MY_NOTIFICATION" />
    </intent-filter>

</receiver>
  1. 直接继承 BroadcastReceiver 在 onReceive()中回调
class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
          var uid= intent?.getStringExtra("uid")
        Log.d(MyBroadcastReceiver.TAG, "onReceive, uid:$uid ")
    }
}

在apk安装的时候,由PMS来完成注册过程。

  1. 发送广播
Intent intent = new Intent();
intent.setAction("com.example.broadcast.MY_NOTIFICATION");
intent.putExtra("uid", "1111111");
// Android8.0(26),无法接受静态注册的广播,因此需要加入指定包名
intent.setPackage(getPackageName());
sendBroadcast(intent);

当app静态注册了广播,在未启动的情况下,系统会拉起app。因此,如果多个app静态注册了系统的广播,那么就会拉起很多的app。 为了优化性能,在Android8.0(26)后静态注册的隐式广播无法接收。建议使用动态注册,或者发送广播时指定包名。

2.2 动态注册

  1. new IntentFilter 对象
MyBroadcastReceiver mReceiver = new MyBroadcastReceiver();
  1. 通过context 上下文注册
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcast.MY_NOTIFICATION");
this.registerReceiver(mReceiver, intentFilter);
  1. 发送广播
Intent intent = new Intent();
intent.setAction("com.example.broadcast.MY_NOTIFICATION");
intent.putExtra("uid", "1111111");
intent.setPackage(getPackageName());
sendBroadcast(intent);
  1. 解绑广播
unregisterReceiver(mReceiver);

当上下文不存在时,需要销毁广播,以防止内存泄漏。 通过上下文注册的广播,生命周期跟当前的context一致。

下面,我们分析的是动态注册过程

三、广播的注册过程

3.1 ContextImpl.registerReceiver()

ContextImpl.java

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

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

3.1.1 registerReceiver()

ContextImpl.java

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

broadcastPermission 用来控制广播权限。 scheduler 是指定当接收到广播时,onReceive()方法执行所在的线程,传入null默认为主线程的handler。

3.1.2 registerReceiverInternal()

ContextImpl.java

 private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context, int flags) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            // 1 获取 IIntentReceiver binder对象,用来给AMS回调回来用
            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 {
                // 2 调用AMS的 registerReceiver()
            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();
        }
    }
  1. LoadApk的 getReceiverDispatcher()方法会返回 IIntentReceiver binder对象,作为Binder服务用来给AMS回调回来用。静态内部类 ReceiverDispatcher.InnerReceiver 就是 IIntentReceiver的子类
  2. 调用AMS的 registerReceiver()

3.2 LoadApk.getReceiverDispatcher

LoadApk.java

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
          Context context, Handler handler,
          Instrumentation instrumentation, boolean registered) {
      synchronized (mReceivers) {
          LoadedApk.ReceiverDispatcher rd = null;
          ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
          // 如果已经注册过了,则从缓存中获取 
          if (registered) {
              map = mReceivers.get(context);
              if (map != null) {
                  rd = map.get(r);
              }
          }
          if (rd == null) {
          // 没有则 new一个 ReceiverDispatcher
              rd = new ReceiverDispatcher(r, context, handler,
                      instrumentation, registered);
              if (registered) {
                  if (map == null) {
                      map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                      mReceivers.put(context, map);
                  }
                  map.put(r, rd);
              }
          } else {
          
              rd.validate(context, handler);
          }
          rd.mForgotten = false;
          // 
          return rd.getIIntentReceiver();
      }
  }

  • 首先从缓存中获取rd ,没有则new 一个 ReceiverDispatcher对象。ReceiverDispatcher 是 LoadApk中的一个静态内部类。
  • 最终,通过 getIIntentReceiver() 返回一个 ReceiverDispatcher.InnerReceiver 对象,我们看看 ReceiverDispatcher就知道了。

3.2.1 ReceiverDispatcher 构造方法

ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                Handler activityThread, Instrumentation instrumentation,
                boolean registered) {
    if (activityThread == null) {
        throw new NullPointerException("Handler must not be null");
    }
    // 创建 InnerReceiver 对象
    mIIntentReceiver = new InnerReceiver(this, !registered);
    mReceiver = receiver;
    mContext = context;
    mActivityThread = activityThread;
    mInstrumentation = instrumentation;
    mRegistered = registered;
    mLocation = new IntentReceiverLeaked(null);
    mLocation.fillInStackTrace();
}

创建 InnerReceiver 对象, InnerReceiver 继承了 IIntentReceiver.Stub类,很明显是一个Binder服务。 getIIntentReceiver()方法返回的就是 InnerReceiver 对象。

3.3 AMS.registerReceiver()

跨进程调用, 直接看 AMS端的方法。

四、AMS端 registerReceiver()

4.1 registerReceiver()

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
        int flags) {
    enforceNotIsolatedCaller("registerReceiver");
    ArrayList<Intent> stickyIntents = null;
    ProcessRecord callerApp = null;
    // ...
    synchronized(this) {
        if (caller != null) {
            // 从 mLruProcesses 中获取 ProcessRecord 进程对象
            callerApp = getRecordForAppLocked(caller);
            ...
            callingUid = callerApp.info.uid;
            callingPid = callerApp.pid;
        } else {
            callerPackage = null;
            callingUid = Binder.getCallingUid();
            callingPid = Binder.getCallingPid();
        }

        instantApp = isInstantApp(callerApp, callerPackage, callingUid);
        userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
        // 获取从app端传递过来的广播的actions列表, 一个广播接受者可能会接收多个action,如自定义、系统的开机、网络变更等
        Iterator<String> actions = filter.actionsIterator();
        if (actions == null) {
            ArrayList<String> noAction = new ArrayList<String>(1);
            noAction.add(null);
            actions = noAction.iterator();
        }

        // Collect stickies of users
        int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
        // 开始遍历 actions 
        while (actions.hasNext()) {
            String action = actions.next();
            // 遍历userIds集合 ,一般情况下就一个
            for (int id : userIds) {
                // 得到 map,key是 action,value是该action对应的所有的intent集合  
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                if (stickies != null) {
                    // 根据action 对应多个intent 
                    ArrayList<Intent> intents = stickies.get(action);
                    if (intents != null) {
                        if (stickyIntents == null) {
                            stickyIntents = new ArrayList<Intent>();
                        }
                        // 加到 stickyIntents 集合
                        stickyIntents.addAll(intents);
                    }
                }
            }
        }
    }

    ArrayList<Intent> allSticky = null;
    if (stickyIntents != null) {
        final ContentResolver resolver = mContext.getContentResolver();
        // Look for any matching sticky broadcasts... 开始查找那些匹配的广播
        for (int i = 0, N = stickyIntents.size(); i < N; i++) {
            Intent intent = stickyIntents.get(i);
            // Don't provided intents that aren't available to instant apps.
            if (instantApp &&
                    (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                continue;
            }
            // If intent has scheme "content", it will need to acccess
            // provider that needs to lock mProviderMap in ActivityThread
            // and also it may need to wait application response, so we
            // cannot lock ActivityManagerService here.
            // 如果匹配
            if (filter.match(resolver, intent, true, TAG) >= 0) {
                if (allSticky == null) {
                    allSticky = new ArrayList<Intent>();
                }
                // 加入到 allSticky 集合
                allSticky.add(intent);
            }
        }
    }

    // The first sticky in the list is returned directly back to the client.
    Intent sticky = allSticky != null ? allSticky.get(0) : null;
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
    if (receiver == null) {
        return sticky;
    }

    synchronized (this) {
        if (callerApp != null && (callerApp.thread == null
                || callerApp.thread.asBinder() != caller.asBinder())) {
            // Original caller already died
            return null;
        }
        // mRegisteredReceivers 表示所有注册过的广播。 key为receiver Binder对象,value为ReceiverList,ReceiverList 是一个集合,表示该广播接收列表。
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
            // 如果该广播从来没有注册过,则创建 ReceiverList对象
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            if (rl.app != null) {
                final int totalReceiversForApp = rl.app.receivers.size();
                
                rl.app.receivers.add(rl);
            } else {
                try {
                 //binder死亡监听
                    receiver.asBinder().linkToDeath(rl, 0);
                } catch (RemoteException e) {
                    return sticky;
                }
                rl.linkedToDeath = true;
            }
            // 存入到 已注册广播map中
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        }...
        // 新建一个 BroadcastFilter对象
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId, instantApp, visibleToInstantApps);
        if (rl.containsFilter(filter)) {
            Slog.w(TAG, "Receiver with filter " + filter
                    + " already registered for pid " + rl.pid
                    + ", callerPackage is " + callerPackage);
        } else {
            // 加入到接收列表中
            rl.add(bf);
              
            // br加入到 mReceiverResolver中 ,后续从这里查找广播接收者
            mReceiverResolver.addFilter(bf);
        }

        // Enqueue broadcasts for all existing stickies that match
        // this filter.
        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, OP_NONE, null, receivers,
                        null, 0, null, null, false, true, true, -1, false,
                        false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }

        return sticky;
    }
}

重点:

  • mRegisteredReceivers 记录所有已注册过的广播。receiver为key,ReceiverList为value。
  • mReceiverResolver :是一个IntentResolve类对象。 给已注册的广播接收者解析intent。 持有 BroadcastFilter 引(IntentFilter的子类)。内部成员 mFilters 集合包含了系统所有已注册的 filters。 后续发送广播时候就从 mReceiverResolver中查找匹配。

至此,动态广播已经注册到系统中了。 我们再看看广播的发送过程。

五、发送广播过程

5.1 App端 ContextImpl.sendBroadcast()

 @Override
    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();
        }
    }

本质上发送广播,就是发送intent,然后从系统中过滤出来和intent-filter规则一样的 intent。

5.2 AMS端 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) {
        // 验证intent合法性
        intent = verifyBroadcastLocked(intent);

        final ProcessRecord callerApp = getRecordForAppLocked(caller);
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();

        final long origId = Binder.clearCallingIdentity();
        try {
            return broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, callingUid, callingPid, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
}

继续调用 broadcastIntentLocked(),传入的 serialized : false,不是有序广播

5.3 broadcastIntentLocked()

@GuardedBy("this")
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 realCallingUid,
        int realCallingPid, int userId) {
    return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType, resultTo,
        resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered,
        sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
        false /* allowBackgroundActivityStarts */);
}

继续,ordered: false 。

5.4 broadcastIntentLocked()

@GuardedBy("this")
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 realCallingUid,
        int realCallingPid, int userId, boolean allowBackgroundActivityStarts) {
        
        //重新创建一个intent 
        intent = new Intent(intent);

         // user用户验证
         
         // 检测系统发送的广播   
            
        // 判断是否是用户被移除、包添加或移除、替换
        
         // Figure out who all will receive this broadcast.
         
        List receivers = null;  // 元素类型为 :ResolveInfo,表示所有的静态广播
        List<BroadcastFilter> registeredReceivers = null; // 所有动态注册的广播

      // Need to resolve the intent to interested receivers... 
        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                 == 0) { //当允许静态注册的广播接收
                 //内部通过PMS解析与这次intent匹配的接收者
            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
        }
        
        
        if (intent.getComponent() == null) {
            if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
               ...
            } else {
                // 通过mReceiverResolver查询动态注册的广播
                registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false /*defaultOnly*/, userId);
            }
        }
        //... 
    
        // 处理并行广播
        final boolean replacePending =
                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

        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. 
            // 处理非有序广播
            if (isCallerSystem) {
                checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                        isProtectedBroadcast, registeredReceivers);
            }
            // 根据intent,通过 broadcastQueueForIntent()方法返回是前台队列 mFgBroadcastQueue 还是后台广播队列 mBgBroadcastQueue。
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            //新建一个 BroadcastRecord对象,表示当前发送的广播
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,resultCode, resultData, resultExtras, ordered, sticky, false, userId,allowBackgroundActivityStarts, timeoutExempt);
            
            final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
            // Note: We assume resultTo is null for non-ordered broadcasts.
            if (!replaced) {
                // 把要发送的广播加入到 并行的广播队列中 mParallelBroadcasts

                queue.enqueueParallelBroadcastLocked(r);
                //处理发送广播
                queue.scheduleBroadcastsLocked();
            }
            // 动态注册广播发送完毕,置空。
            registeredReceivers = null;
            NR = 0;
        }

        // 合并 registeredReceivers 到 receivers

        while (ir < NR) {
            if (receivers == null) {
                receivers = new ArrayList();
            }
            receivers.add(registeredReceivers.get(ir));
            ir++;
        }

 
        // 得到所有的静态注册和动态注册的广播,开始处理串行广播
          if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            
            // 根据intent 获取 BroadcastQueue 
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            // 创建一个br对象,把 receivers传进去
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                    resultData, resultExtras, ordered, sticky, false, userId,
                    allowBackgroundActivityStarts, timeoutExempt);

            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);

            final BroadcastRecord oldRecord =
                    replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
            if (oldRecord != null) {
                //...
            } else {
                // 把这次发送广播的工作加入到串行广播队列中
                queue.enqueueOrderedBroadcastLocked(r);
                // 开始处理广播发送
                queue.scheduleBroadcastsLocked();
            }
        } else {
           //...
        }

        return ActivityManager.BROADCAST_SUCCESS;
        

}

重点:

  1. 当允许静态注册广播接收时,收集所有静态注册的广播
  2. 通过AMS的成员变量 mReceiverResolver查询动态注册的广播
  3. 处理并行广播:根据intent,通过 broadcastQueueForIntent()方法返回是前台队列 mFgBroadcastQueue 还是后台广播队列 mBgBroadcastQueue
  4. 开始处理并行广播发送
  5. 合并 registeredReceivers 到 receivers,处理串行广播
  6. 开始处理串行广播发送

5.4.1 broadcastQueueForIntent()

AMS

BroadcastQueue broadcastQueueForIntent(Intent intent) {
    if (isOnOffloadQueue(intent.getFlags())) {
        if (DEBUG_BROADCAST_BACKGROUND) {
            Slog.i(TAG_BROADCAST,
                    "Broadcast intent " + intent + " on offload queue");
        }
        return mOffloadBroadcastQueue;
    }

    final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
    if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
            "Broadcast intent " + intent + " on "
            + (isFg ? "foreground" : "background") + " queue");
    return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}

根据intent来决定加入到前台广播队列还是后台广播队列。

5.4.2 enqueueParallelBroadcastLocked()

BroadcastQueue.java

public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
    mParallelBroadcasts.add(r);
    enqueueBroadcastHelper(r);
}

mParallelBroadcasts 表示并行广播列表。

5.4.3 enqueueOrderedBroadcastLocked()

BroadcastQueue.java

public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    mDispatcher.enqueueOrderedBroadcastLocked(r);
    enqueueBroadcastHelper(r);
}

5.4.4 enqueueOrderedBroadcastLocked()

BroadcastDispatcher.java.java

void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    mOrderedBroadcasts.add(r);
}

mOrderedBroadcasts 表示串行广播列表。

5.5 广播发送总结

  1. 发送并行广播
  • 只有动态注册的广播才能并行处理
  • 根据intent找到 前台或后台 BroadcastQueue队列
  • 新建 BroadcastRecord对象
  • enqueueParallelBroadcastLocked()加入到并行队列中
  • scheduleBroadcastsLocked() 开始处理
  1. 发送串行广播
  • 所有静态注册的广播和动态注册的广播合并到一个列表中,统一串行处理
  • 根据intent找到 前台或后台 BroadcastQueue队列
  • 新建 BroadcastRecord对象
  • enqueueOrderedBroadcastLocked()加入到 BroadcastDispatcher 的串行队列中
  • scheduleBroadcastsLocked() 开始处理

因此,不管是并行广播,还是串行广播,最终都会调用 scheduleBroadcastsLocked() 开始处理。

六、AMS端 处理广播过程

6.1 scheduleBroadcastsLocked()

BroadcastQueue.java

public void scheduleBroadcastsLocked() {
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
            + mQueueName + "]: current="
            + mBroadcastsScheduled);

    if (mBroadcastsScheduled) {
        return;
    }
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}

发送了一个消息到 BroadcastHandler。BroadcastHandler是在 BroadcastQueue构造方法中创建的,它使用的是AMS的looper。

 private final class BroadcastHandler extends Handler {
        public BroadcastHandler(Looper looper) {
            super(looper, null, true);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
                            + mQueueName + "]");
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
            }
        }
    }

6.2 processNextBroadcast()

BroadcastQueue.java

final void processNextBroadcast(boolean fromMsg) {
    synchronized (mService) {
        processNextBroadcastLocked(fromMsg, false);
    }
}

6.3 processNextBroadcastLocked()

BroadcastQueue.java

 final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;

        mService.updateCpuStats();
        if (fromMsg) {
                mBroadcastsScheduled = false;
            }
        
            // First, deliver any non-serialized broadcasts right away.
            // 首选,开始处理并行广播
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0); // 拿到br对象
                r.dispatchTime = SystemClock.uptimeMillis();
                r.dispatchClockTime = System.currentTimeMillis();
        
                if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                    Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
                        System.identityHashCode(r));
                    Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
                        System.identityHashCode(r));
                }
        
                final int N = r.receivers.size();
             
                        // 遍历所有并行广播的接收者 
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
      
                    // 投递广播到每一个mei'y接收者
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }
                addBroadcastToHistoryLocked(r);
                
            }
            // 接着处理串行广播,也就是有序广播
            
            do {
                final long now = SystemClock.uptimeMillis();
                
                r = mDispatcher.getNextBroadcastLocked(now);

                if (r == null) {
                    // No more broadcasts are deliverable right now, so all done!
                    mDispatcher.scheduleDeferralCheckLocked(false);
                    mService.scheduleAppGcsLocked();
                    if (looped) {
                        // If we had finished the last ordered broadcast, then
                        // make sure all processes have correct oom and sched
                        // adjustments.
                        mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
                    }

                    // when we have no more ordered broadcast on this queue, stop logging
                    if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {
                        mLogLatencyMetrics = false;
                    }

                    return;
                }

                boolean forceReceive = false;

                // Ensure that even if something goes awry with the timeout
                // detection, we catch "hung" broadcasts here, discard them,
                // and continue to make progress.
                //
                // This is only done if the system is ready so that early-stage receivers
                // don't get executed with timeouts; and of course other timeout-
                // exempt broadcasts are ignored.
                int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
                if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
                    if ((numReceivers > 0) &&
                            (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
                      
                        broadcastTimeoutLocked(false); // forcibly finish this broadcast
                        forceReceive = true;
                        r.state = BroadcastRecord.IDLE;
                    }
                }

                if (r.state != BroadcastRecord.IDLE) {
                    if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
                            "processNextBroadcast("
                            + mQueueName + ") called when not idle (state="
                            + r.state + ")");
                    return;
                }

                // Is the current broadcast is done for any reason?
                if (r.receivers == null || r.nextReceiver >= numReceivers
                        || r.resultAbort || forceReceive) {
                    // Send the final result if requested
                    if (r.resultTo != null) {
                        boolean sendResult = true;

                        // if this was part of a split/deferral complex, update the refcount and only
                        // send the completion when we clear all of them
                        if (r.splitToken != 0) {
                            int newCount = mSplitRefcounts.get(r.splitToken) - 1;
                            if (newCount == 0) {
                                // done!  clear out this record's bookkeeping and deliver
                                if (DEBUG_BROADCAST_DEFERRAL) {
                                    Slog.i(TAG_BROADCAST,
                                            "Sending broadcast completion for split token "
                                            + r.splitToken + " : " + r.intent.getAction());
                                }
                                mSplitRefcounts.delete(r.splitToken);
                            } else {
                                // still have some split broadcast records in flight; update refcount
                                // and hold off on the callback
                                if (DEBUG_BROADCAST_DEFERRAL) {
                                    Slog.i(TAG_BROADCAST,
                                            "Result refcount now " + newCount + " for split token "
                                            + r.splitToken + " : " + r.intent.getAction()
                                            + " - not sending completion yet");
                                }
                                sendResult = false;
                                mSplitRefcounts.put(r.splitToken, newCount);
                            }
                        }
                        if (sendResult) {
                            try {
                               // 
                                performReceiveLocked(r.callerApp, r.resultTo,
                                        new Intent(r.intent), r.resultCode,
                                        r.resultData, r.resultExtras, false, false, r.userId);
                                // Set this to null so that the reference
                                // (local and remote) isn't kept in the mBroadcastHistory.
                                r.resultTo = null;
                            } catch (RemoteException e) {
                                r.resultTo = null;
                                Slog.w(TAG, "Failure ["
                                        + mQueueName + "] sending broadcast result of "
                                        + r.intent, e);
                            }
                        }
                    }

                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
                    cancelBroadcastTimeoutLocked();

                    // ... and on to the next...
                    addBroadcastToHistoryLocked(r);
                    if (r.intent.getComponent() == null && r.intent.getPackage() == null
                            && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                        // This was an implicit broadcast... let's record it for posterity.
                        mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                                r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
                    }
                    mDispatcher.retireBroadcastLocked(r);
                    r = null;
                    looped = true;
                    continue;
                }

                // Check whether the next receiver is under deferral policy, and handle that
                // accordingly.  If the current broadcast was already part of deferred-delivery
                // tracking, we know that it must now be deliverable as-is without re-deferral.
                if (!r.deferred) {
                    final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));
                    if (mDispatcher.isDeferringLocked(receiverUid)) {
                       
                        // If this is the only (remaining) receiver in the broadcast, "splitting"
                        // doesn't make sense -- just defer it as-is and retire it as the
                        // currently active outgoing broadcast.
                        BroadcastRecord defer;
                        if (r.nextReceiver + 1 == numReceivers) {
                            if (DEBUG_BROADCAST_DEFERRAL) {
                                Slog.i(TAG_BROADCAST, "Sole receiver of " + r
                                        + " is under deferral; setting aside and proceeding");
                            }
                            defer = r;
                            mDispatcher.retireBroadcastLocked(r);
                        } else {
                            // Nontrivial case; split out 'uid's receivers to a new broadcast record
                            // and defer that, then loop and pick up continuing delivery of the current
                            // record (now absent those receivers).

                            // The split operation is guaranteed to match at least at 'nextReceiver'
                            defer = r.splitRecipientsLocked(receiverUid, r.nextReceiver);
                            
                            // Track completion refcount as well if relevant
                            if (r.resultTo != null) {
                                int token = r.splitToken;
                                if (token == 0) {
                                    // first split of this record; refcount for 'r' and 'deferred'
                                    r.splitToken = defer.splitToken = nextSplitTokenLocked();
                                    mSplitRefcounts.put(r.splitToken, 2);
                                    if (DEBUG_BROADCAST_DEFERRAL) {
                                        Slog.i(TAG_BROADCAST,
                                                "Broadcast needs split refcount; using new token "
                                                + r.splitToken);
                                    }
                                } else {
                                    // new split from an already-refcounted situation; increment count
                                    final int curCount = mSplitRefcounts.get(token);
                                    if (DEBUG_BROADCAST_DEFERRAL) {
                                        if (curCount == 0) {
                                            Slog.wtf(TAG_BROADCAST,
                                                    "Split refcount is zero with token for " + r);
                                        }
                                    }
                                    mSplitRefcounts.put(token, curCount + 1);
                                    if (DEBUG_BROADCAST_DEFERRAL) {
                                        Slog.i(TAG_BROADCAST, "New split count for token " + token
                                                + " is " + (curCount + 1));
                                    }
                                }
                            }
                        }
                        mDispatcher.addDeferredBroadcast(receiverUid, defer);
                        r = null;
                        looped = true;
                        continue;
                    }
                }
            } while (r == null);

            
            // 获取有序广播的下一个接收者
            
            // Get the next receiver...
            int recIdx = r.nextReceiver++;

            // Keep track of when this receiver started, and make sure there
            // is a timeout message pending to kill it if need be.
            r.receiverTime = SystemClock.uptimeMillis();
            if (recIdx == 0) {
                r.dispatchTime = r.receiverTime;
                r.dispatchClockTime = System.currentTimeMillis();
            if (! mPendingBroadcastTimeoutMessage) {
                long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
                
                setBroadcastTimeoutLocked(timeoutTime);
            }

            final BroadcastOptions brOptions = r.options;
            final Object nextReceiver = r.receivers.get(recIdx);

            //处理下一条有序广播
            
            if (nextReceiver instanceof BroadcastFilter) {
                // Simple case: this is a registered receiver who gets
                // a direct call.
                BroadcastFilter filter = (BroadcastFilter)nextReceiver;
                
                deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
                if (r.receiver == null || !r.ordered) {
                    // The receiver has already finished, so schedule to
                    // process the next one.
                    
                    r.state = BroadcastRecord.IDLE;
                    // 开始处理下一条广播
                    scheduleBroadcastsLocked();
                } else {
                    if (filter.receiverList != null) {
                        maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                        // r is guaranteed ordered at this point, so we know finishReceiverLocked()
                        // will get a callback and handle the activity start token lifecycle.
                    }
                    if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                        scheduleTempWhitelistLocked(filter.owningUid,
                                brOptions.getTemporaryAppWhitelistDuration(), r);
                    }
                }
                return;
            }

            // 如果进程已经拉起,则执行广播处理逻辑
            // Is this receiver's application already running?
            if (app != null && app.thread != null && !app.killed) {
                try {
                    app.addPackage(info.activityInfo.packageName,
                            info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
                    maybeAddAllowBackgroundActivityStartsToken(app, r);
                    processCurBroadcastLocked(r, app, skipOomAdj);
                    return;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when sending broadcast to "
                          + r.curComponent, e);
                } catch (RuntimeException e) {
                    Slog.wtf(TAG, "Failed sending broadcast to "
                            + r.curComponent + " with " + r.intent, e);
                    // If some unexpected exception happened, just skip
                    // this broadcast.  At this point we are not in the call
                    // from a client, so throwing an exception out from here
                    // will crash the entire system instead of just whoever
                    // sent the broadcast.
                    logBroadcastReceiverDiscardLocked(r);
                    finishReceiverLocked(r, r.resultCode, r.resultData,
                            r.resultExtras, r.resultAbort, false);
                    scheduleBroadcastsLocked();
                    // We need to reset the state if we failed to start the receiver.
                    r.state = BroadcastRecord.IDLE;
                    return;
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }

            // 如果进程没有拉起,则拉起进程
            
            // Not running -- get it started, to be executed when the app comes up.
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                    "Need to start app ["
                    + mQueueName + "] " + targetProcess + " for broadcast " + r);
            if ((r.curApp=mService.startProcessLocked(targetProcess,
                    info.activityInfo.applicationInfo, true,
                    r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
                    new HostingRecord("broadcast", r.curComponent),
                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                            == null) {
                // Ah, this recipient is unavailable.  Finish it if necessary,
                // and mark the broadcast record as ready for the next.
               
                logBroadcastReceiverDiscardLocked(r);
                finishReceiverLocked(r, r.resultCode, r.resultData,
                        r.resultExtras, r.resultAbort, false);
                scheduleBroadcastsLocked();
                r.state = BroadcastRecord.IDLE;
                return;
            }

            //...

主要分为四个部分:

  1. 开始处理并行广播
  2. 处理串行广播
  3. 获取串行广播的下一个receiver
  4. 获取下一条串行广播
  5. 当前进程是否已经拉起?

6.3.1 开始处理并行广播

 while (mParallelBroadcasts.size() > 0) {
        r = mParallelBroadcasts.remove(0); // 拿到br对象
        r.dispatchTime = SystemClock.uptimeMillis();
        r.dispatchClockTime = System.currentTimeMillis();

        if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
                System.identityHashCode(r));
            Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
                System.identityHashCode(r));
        }

        final int N = r.receivers.size();

                // 遍历所有并行广播的接收者 
        for (int i=0; i<N; i++) {
            Object target = r.receivers.get(i);

            // 投递广播到每一个接收者
            deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
        }
        addBroadcastToHistoryLocked(r);

    }

遍历 mParallelBroadcasts 并行队列,得到每一个要发送的广播,发送给广播对应的所有接收者。由于是一次发给所有接收者,因此不存在广播超时的问题。

6.3.2 处理串行/有序广播

// 接着处理串行广播,也就是有序广播         
do {
    final long now = SystemClock.uptimeMillis();
    // 获取第一个有序广播接收者 
    r = mDispatcher.getNextBroadcastLocked(now);

    if (r == null) {
        // 如果为空,则表示有序广播已经全部发送完毕
        // No more broadcasts are deliverable right now, so all done!
        mDispatcher.scheduleDeferralCheckLocked(false);
        // 调度gc
        mService.scheduleAppGcsLocked();
        if (looped) {
            // If we had finished the last ordered broadcast, then
            // make sure all processes have correct oom and sched
            // adjustments.
            // 更新oom级别
            mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
        }

        // when we have no more ordered broadcast on this queue, stop logging
        if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {
            mLogLatencyMetrics = false;
        }
        // 有序广播处理结束
        return;
    }

    boolean forceReceive = false;

    // Ensure that even if something goes awry with the timeout
    // detection, we catch "hung" broadcasts here, discard them,
    // and continue to make progress.
    //
    // This is only done if the system is ready so that early-stage receivers
    // don't get executed with timeouts; and of course other timeout-
    // exempt broadcasts are ignored.
    
    // 该有序广播对应的所有接收者 
    int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
  
    if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
        if ((numReceivers > 0) &&
                (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
            // 如果当前广播分发超时,则强制结束。同时发送ANR消息到 ProcessRecord中。
            broadcastTimeoutLocked(false); // forcibly finish this broadcast
            forceReceive = true;
            r.state = BroadcastRecord.IDLE;
        }
    }

    if (r.state != BroadcastRecord.IDLE) {
       
        return;
    }

    // Is the current broadcast is done for any reason?
     // 如果当前广播的所有接收者都已经处理完毕,或者被终止,那么就认为当前广播已经处理完成,则需要移除当前广播了,且置空,继续处理下一条广播。
    if (r.receivers == null || r.nextReceiver >= numReceivers
            || r.resultAbort || forceReceive) {
        // Send the final result if requested
        if (r.resultTo != null) {
            boolean sendResult = true;
            //...
            if (sendResult) {
                try {
                   // 投递广播到app,回调onReceive()
                    performReceiveLocked(r.callerApp, r.resultTo,
                            new Intent(r.intent), r.resultCode,
                            r.resultData, r.resultExtras, false, false, r.userId);
                    // Set this to null so that the reference
                    // (local and remote) isn't kept in the mBroadcastHistory.
                    r.resultTo = null;
                }//...
            }
        }

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
        // 取消ANR超时消息 
        cancelBroadcastTimeoutLocked();

        // ... and on to the next...
        addBroadcastToHistoryLocked(r);
        if (r.intent.getComponent() == null && r.intent.getPackage() == null
                && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            // This was an implicit broadcast... let's record it for posterity.
            mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                    r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
        }
        //移除已经发送过的br
        mDispatcher.retireBroadcastLocked(r);
        // 置空r,继续下一条广播处理
        r = null;
        looped = true;
        continue;
    }
    //...
} while (r == null);

mConstants.TIMEOUT的值为:前台广播是10s,后台广播则是60s。

static final int BROADCAST_FG_TIMEOUT = 101000; static final int BROADCAST_BG_TIMEOUT = 601000;

广播超时阈值的时间为:2 * mConstants.TIMEOUT * numReceivers 。也就是说是超时的2倍再乘以当前广播接收者的数量。因此,广播接受者数量越多,超时的阈值就越大。

  • 从 mDispatcher中的 mOrderedBroadcasts队列中获取第一个广播 BroadcastRecord对象 br
  • 如果br为空则表示有序广播已经处理完毕,那么就调度gc,更新oom级别。处理结束。
  • 如果不为空,则获取该广播对应的所有的接收者
  • 如果该广播已经超时,那么就强制停止,同时发送ANR消息到 ProcessRecord中。
  • 如果没有超时,且当前广播的所有接收者都已经处理完毕或者被终止,那么就认为当前广播已经处理完成,则需要移除当前广播,回调onReceive()方法,取消超时消息,移除当前br,br置空,继续处理下一条有序广播。

因为是一次处理,所以如果该广播的接收者还没有处理完成,则获取下一个接收者receiver。

6.3.3 获取有序广播的下一个receiver

// 获取有序广播的下一个接收者            
// Get the next receiver...
int recIdx = r.nextReceiver++;

// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
    r.dispatchTime = r.receiverTime;
    r.dispatchClockTime = System.currentTimeMillis();
if (! mPendingBroadcastTimeoutMessage) {
    long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
    // 发送一个 超时消息
    setBroadcastTimeoutLocked(timeoutTime);
}

final BroadcastOptions brOptions = r.options;
final Object nextReceiver = r.receivers.get(recIdx);

//处理下一个接收者
if (nextReceiver instanceof BroadcastFilter) {
    // Simple case: this is a registered receiver who gets
    // a direct call.
    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
    // 对于动态广播,则调用 deliverToRegisteredReceiverLocked() 方法
    deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
    if (r.receiver == null || !r.ordered) {
        // The receiver has already finished, so schedule to
        // process the next one.
        r.state = BroadcastRecord.IDLE;
        // 开始处理下一条广播
        scheduleBroadcastsLocked();
    } else {
        if (filter.receiverList != null) {
            maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
            // r is guaranteed ordered at this point, so we know finishReceiverLocked()
            // will get a callback and handle the activity start token lifecycle.
        }
        if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
            scheduleTempWhitelistLocked(filter.owningUid,
                    brOptions.getTemporaryAppWhitelistDuration(), r);
        }
    }
    return;
}

获取当前广播的下一个接收者,对于动态广播,则调用 deliverToRegisteredReceiverLocked() 方法开始处理。 如果所有接收者处理完成,则继续处理下一条广播。

6.3.4 当前进程是否拉起?

// 如果进程已经拉起,则执行广播处理逻辑
// Is this receiver's application already running?
if (app != null && app.thread != null && !app.killed) {
    try {
        app.addPackage(info.activityInfo.packageName,
                info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
        maybeAddAllowBackgroundActivityStartsToken(app, r);
        // 处理静态广播逻辑 
        processCurBroadcastLocked(r, app, skipOomAdj);
        return;
    } catch (RemoteException e) {
        Slog.w(TAG, "Exception when sending broadcast to "
              + r.curComponent, e);
    } catch (RuntimeException e) {
        Slog.wtf(TAG, "Failed sending broadcast to "
                + r.curComponent + " with " + r.intent, e);
        // If some unexpected exception happened, just skip
        // this broadcast.  At this point we are not in the call
        // from a client, so throwing an exception out from here
        // will crash the entire system instead of just whoever
        // sent the broadcast.
        logBroadcastReceiverDiscardLocked(r);
        finishReceiverLocked(r, r.resultCode, r.resultData,
                r.resultExtras, r.resultAbort, false);
        scheduleBroadcastsLocked();
        // We need to reset the state if we failed to start the receiver.
        r.state = BroadcastRecord.IDLE;
        return;
    }

    // If a dead object exception was thrown -- fall through to
    // restart the application.
}

// 如果进程没有拉起,则拉起进程

// Not running -- get it started, to be executed when the app comes up.
// 如果没有拉起则 调用 startProcessLocked()拉起进程
if ((r.curApp=mService.startProcessLocked(targetProcess,
        info.activityInfo.applicationInfo, true,
        r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
        new HostingRecord("broadcast", r.curComponent),
        (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                == null) {
    // Ah, this recipient is unavailable.  Finish it if necessary,
    // and mark the broadcast record as ready for the next.
    
    logBroadcastReceiverDiscardLocked(r);
    // 如果进程拉起失败,则结束当前广播
    finishReceiverLocked(r, r.resultCode, r.resultData,
            r.resultExtras, r.resultAbort, false);
    scheduleBroadcastsLocked();
    r.state = BroadcastRecord.IDLE;
    return;
}

如果进程已经存在,则调用 processCurBroadcastLocked() 处理静态广播接收者逻辑,否则则拉起进程。

总结:

  • 如果是动态广播接收者,则调用deliverToRegisteredReceiverLocked处理;
  • 如果是静态广播接收者,且对应进程已经创建,则调用processCurBroadcastLocked处理;
  • 如果是静态广播接收者,且对应进程尚未创建,则调用startProcessLocked创建进程。

接下来,看看deliverToRegisteredReceiverLocked的处理流程:

6.4 deliverToRegisteredReceiverLocked()

BroadcastQueue.java

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered, int index) {
        //...
try {
       
        if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
            // Skip delivery if full backup in progress
            // If it's an ordered broadcast, we need to continue to the next receiver.
            if (ordered) {
                skipReceiverLocked(r);
            }
        } else {
            r.receiverTime = SystemClock.uptimeMillis();
            maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
            // 继续执行 
            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                    new Intent(r.intent), r.resultCode, r.resultData,
                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
            // parallel broadcasts are fire-and-forget, not bookended by a call to
            // finishReceiverLocked(), so we manage their activity-start token here
            if (r.allowBackgroundActivityStarts && !r.ordered) {
                postActivityStartTokenRemoval(filter.receiverList.app, r);
            }
        }
        if (ordered) {
            r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
    } catch (RemoteException e) {
        Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
        // Clean up ProcessRecord state related to this broadcast attempt
        if (filter.receiverList.app != null) {
            filter.receiverList.app.removeAllowBackgroundActivityStartsToken(r);
            if (ordered) {
                filter.receiverList.app.curReceivers.remove(r);
            }
        }
        // And BroadcastRecord state related to ordered delivery, if appropriate
        if (ordered) {
            r.receiver = null;
            r.curFilter = null;
            filter.receiverList.curBroadcast = null;
        }
    }
}

6.5 performReceiveLocked()

BroadcastQueue.java

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) {
            // If we have an app thread, do the call through that so it is
            // correctly ordered with other one-way calls.
            try {
            // 调用 applicationThread的对象 
                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
                        
            // 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 {
        // 调用者进程不存在,则直接调用 IIntentReceiver的 performReceive()
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
}

  • 调用者进程存在,则通过binder,调用APP端的scheduleRegisteredReceiver()
  • 调用者进程不存在,则直接调用 IIntentReceiver的 performReceive()

七、App端接收

7.1 scheduleRegisteredReceiver()

ActivityThread.ApplicationThread.java


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);
}

IIntentReceiver 是 LoadApk中的静态内部类 ReceiverDispatcher中的内部类 InnerReceiver

static final class ReceiverDispatcher {

    final static class InnerReceiver extends IIntentReceiver.Stub {
        final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
        final LoadedApk.ReceiverDispatcher mStrongRef;

7.2 performReceive()

LoadApk.java的内部类 InnerReceiver.java

@Override
public void performReceive(Intent intent, int resultCode, String data,
        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    final LoadedApk.ReceiverDispatcher rd;
    if (intent == null) {
        Log.wtf(TAG, "Null intent received");
        rd = null;
    } else {
        rd = mDispatcher.get();
    }
   
    if (rd != null) {
        rd.performReceive(intent, resultCode, data, extras,
                ordered, sticky, sendingUser);
    } else {
        // The activity manager dispatched a broadcast to a registered
        // receiver in this process, but before it could be delivered the
        // receiver was unregistered.  Acknowledge the broadcast on its
        // behalf so that the system's broadcast sequence can continue.
        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                "Finishing broadcast to unregistered receiver");
        IActivityManager mgr = ActivityManager.getService();
        try {
            if (extras != null) {
                extras.setAllowFds(false);
            }
            mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

调用了 LoadedApk.ReceiverDispatcher 的performReceive()方法。

7.3 performReceive()

LoadedApk.ReceiverDispatcher.java

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);
            }
        }
        // 开始执行 args 
        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);
            }
        }
    }

创建了一个 Args 对象,把args的 runnable 切换到了主线程运行(默认为主线程)。继续看看 runnable的run()方法。

7.4 getRunnable()

final class Args extends BroadcastReceiver.PendingResult {
        private Intent mCurIntent;
        private final boolean mOrdered;
        private boolean mDispatched;
        private boolean mRunCalled;

        public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                boolean ordered, boolean sticky, int sendingUser) {
            super(resultCode, resultData, resultExtras,
                    mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                    sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
            mCurIntent = intent;
            mOrdered = ordered;
        }

        public final Runnable getRunnable() {
            return () -> {
                final BroadcastReceiver receiver = mReceiver;
                final boolean ordered = mOrdered;


                final IActivityManager mgr = ActivityManager.getService();
                final Intent intent = mCurIntent;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched
                            + (mRunCalled ? ", run() has already been called" : ""));
                }

                mCurIntent = null;
                mDispatched = true;
                mRunCalled = true;
                if (receiver == null || intent == null || mForgotten) {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing null broadcast to " + mReceiver);
                        sendFinished(mgr);
                    }
                    return;
                }

                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
                try {
                    ClassLoader cl = mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    intent.prepareToEnterProcess();
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    // 回调 onReceive()方法
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing failed broadcast to " + mReceiver);
                        sendFinished(mgr);
                    }
                    if (mInstrumentation == null ||
                            !mInstrumentation.onException(mReceiver, e)) {
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        throw new RuntimeException(
                                "Error receiving broadcast " + intent
                                        + " in " + mReceiver, e);
                    }
                }

                if (receiver.getPendingResult() != null) {
                // 调用finish方法
                    finish();
                }
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            };
        }
    }
  • 回调 广播接收者的 onReceive()方法
  • Args继承了 BroadcastReceiver.PendingResult,因此调用了其finish()方法

7.4.1 finish()

BroadcastReceiver.java

完成当前广播的发送,发送当前结果,同时执行下一个广播。

public final void finish() {
    if (mType == TYPE_COMPONENT) {
        // TYPE_COMPONENT表示静态注册广播
        final IActivityManager mgr = ActivityManager.getService();
        if (QueuedWork.hasPendingWork()) {
           
            QueuedWork.queue(new Runnable() {
                @Override public void run() {
                   
                    sendFinished(mgr);
                }
            }, false);
        } else {
           
            sendFinished(mgr);
        }
    } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
          // 动态注册的广播
        final IActivityManager mgr = ActivityManager.getService();
        sendFinished(mgr);
    }
}

不管是静态注册还是动态注册的广播,最终都会调用 sendFinished(mgr) 方法。

7.4.2 sendFinished()

BroadcastReceiver.java

public void sendFinished(IActivityManager am) {
    synchronized (this) {
        if (mFinished) {
            throw new IllegalStateException("Broadcast already finished");
        }
        mFinished = true;

        try {
            if (mResultExtras != null) {
                mResultExtras.setAllowFds(false);
            }
            if (mOrderedHint) {
            // 串行广播 调用AMS的方法
                am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                        mAbortBroadcast, mFlags);
            } else {
                // This broadcast was sent to a component; it is not ordered,
                // but we still need to tell the activity manager we are done.
                // 并行广播 
                am.finishReceiver(mToken, 0, null, null, false, mFlags);
            }
        } catch (RemoteException ex) {
        }
    }
}

八、AMS端finishReceiver()

8.1 AMS.finishReceiver()

public void finishReceiver(IBinder who, int resultCode, String resultData,
        Bundle resultExtras, boolean resultAbort, int flags) {
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);

    // Refuse possible leaked file descriptors
    if (resultExtras != null && resultExtras.hasFileDescriptors()) {
        throw new IllegalArgumentException("File descriptors passed in Bundle");
    }

    final long origId = Binder.clearCallingIdentity();
    try {
        boolean doNext = false;
        BroadcastRecord r;
        BroadcastQueue queue;

        synchronized(this) {
            if (isOnOffloadQueue(flags)) {
                queue = mOffloadBroadcastQueue;
            } else {
                queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
                        ? mFgBroadcastQueue : mBgBroadcastQueue;
            }

            r = queue.getMatchingOrderedReceiver(who);
            if (r != null) {
                doNext = r.queue.finishReceiverLocked(r, resultCode,
                    resultData, resultExtras, resultAbort, true);
            }
            if (doNext) {
                r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
            }
            // updateOomAdjLocked() will be done here
            trimApplicationsLocked(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
        }

    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

8.2 finishReceiverLocked()

BroadcastQueue.java

public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
        String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
    final int state = r.state;
    final ActivityInfo receiver = r.curReceiver;
    final long finishTime = SystemClock.uptimeMillis();
    final long elapsed = finishTime - r.receiverTime;
    r.state = BroadcastRecord.IDLE;
    if (state == BroadcastRecord.IDLE) {
        Slog.w(TAG_BROADCAST, "finishReceiver [" + mQueueName + "] called but state is IDLE");
    }
    if (r.allowBackgroundActivityStarts && r.curApp != null) {
        if (elapsed > mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT) {
            // if the receiver has run for more than allowed bg activity start timeout,
            // just remove the token for this process now and we're done
            r.curApp.removeAllowBackgroundActivityStartsToken(r);
        } else {
            // It gets more time; post the removal to happen at the appropriate moment
            postActivityStartTokenRemoval(r.curApp, r);
        }
    }
    // If we're abandoning this broadcast before any receivers were actually spun up,
    // nextReceiver is zero; in which case time-to-process bookkeeping doesn't apply.
    if (r.nextReceiver > 0) {
        r.duration[r.nextReceiver - 1] = elapsed;
    }

    // if this receiver was slow, impose deferral policy on the app.  This will kick in
    // when processNextBroadcastLocked() next finds this uid as a receiver identity.
    if (!r.timeoutExempt) {
        if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
            // Core system packages are exempt from deferral policy
            if (!UserHandle.isCore(r.curApp.uid)) {
                if (DEBUG_BROADCAST_DEFERRAL) {
                    Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1)
                            + " was slow: " + receiver + " br=" + r);
                }
                if (r.curApp != null) {
                    mDispatcher.startDeferring(r.curApp.uid);
                } else {
                    Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r);
                }
            } else {
                if (DEBUG_BROADCAST_DEFERRAL) {
                    Slog.i(TAG_BROADCAST, "Core uid " + r.curApp.uid
                            + " receiver was slow but not deferring: " + receiver + " br=" + r);
                }
            }
        }
    } else {
        if (DEBUG_BROADCAST_DEFERRAL) {
            Slog.i(TAG_BROADCAST, "Finished broadcast " + r.intent.getAction()
                    + " is exempt from deferral policy");
        }
    }

    r.receiver = null;
    r.intent.setComponent(null);
    if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
        r.curApp.curReceivers.remove(r);
    }
    if (r.curFilter != null) {
        r.curFilter.receiverList.curBroadcast = null;
    }
    r.curFilter = null;
    r.curReceiver = null;
    r.curApp = null;
    mPendingBroadcast = null;

    r.resultCode = resultCode;
    r.resultData = resultData;
    r.resultExtras = resultExtras;
    if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
        r.resultAbort = resultAbort;
    } else {
        r.resultAbort = false;
    }

    // If we want to wait behind services *AND* we're finishing the head/
    // active broadcast on its queue
    if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
            && r.queue.mDispatcher.getActiveBroadcastLocked() == r) {
        ActivityInfo nextReceiver;
        if (r.nextReceiver < r.receivers.size()) {
            Object obj = r.receivers.get(r.nextReceiver);
            nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null;
        } else {
            nextReceiver = null;
        }
        // Don't do this if the next receive is in the same process as the current one.
        if (receiver == null || nextReceiver == null
                || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
                || !receiver.processName.equals(nextReceiver.processName)) {
            // In this case, we are ready to process the next receiver for the current broadcast,
            // but are on a queue that would like to wait for services to finish before moving
            // on.  If there are background services currently starting, then we will go into a
            // special state where we hold off on continuing this broadcast until they are done.
            if (mService.mServices.hasBackgroundServicesLocked(r.userId)) {
                Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
                r.state = BroadcastRecord.WAITING_SERVICES;
                return false;
            }
        }
    }

    r.curComponent = null;

    // We will process the next receiver right now if this is finishing
    // an app receiver (which is always asynchronous) or after we have
    // come back from calling a receiver.
    return state == BroadcastRecord.APP_RECEIVE
            || state == BroadcastRecord.CALL_DONE_RECEIVE;
}

九、总结

9.1 关于串行/并行处理

  1. 发送串行广播
  • 静态注册的广播 按照串行处理
  • 动态注册的广播 按照串行处理
  1. 发送并行广播
  • 静态注册的广播 按照串行处理
  • 动态注册的广播 按照并行处理

让静态广播始终串行处理的原因是,一般情况下静态广播的应用都是未启动的,当发送广播时防止瞬间拉起大量应用。

9.2 广播ANR

并行广播由于是一次分发到每个receiver,因此没有ANR情况。串行广播是一个接着一个处理,因此存在两种ANR情况:

  1. 当前广播处理的总耗时超过阈值:2*mConstants.TIMEOUT*mReceiverNum
  2. 当前广播的某个receiver执行时间超过阈值: mConstants.TIMEOUT。
  • mConstants.TIMEOUT的值: 前台广播为10s,后台广播为60s。
  • mReceiverNum: 表示当前广播的所有接收者的数量。

十、参考

developer.android.com/guide/compo…

gityuan.com/2016/06/04/…

liuwangshu.cn/framework/c…