Android 广播优先级研究


声明:本文转载自https://my.oschina.net/ososchina/blog/1610161,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

广播介绍

Android中广播主要分为:有序广播、无序广播、粘性广播、局部广播。当然粘性广播也可以分为有序粘性广播和无序粘性广播,在这里我们探讨一下有序广播和无序广播。

· 普通广播(Normal Broadcast):用sendBroadcast()方法发送。

普通广播是完全异步的,逻辑上可以在同一时刻被所有匹配的接受者接收到,消息传递效率高,缺点是接受者不能将处理结果传递给下一个接收者,也无法终止广播传播。

 

· 有序广播(Ordered Broadcast):用sendOrderedBroadcast()方法发送。

有序广播的接收者们将按照事先生命的优先级依次接收,数越大优先级越高(取值范围:-1000~1000),优先级可以声明 在<intent-filter android:priority="n".../>,也可以调用IntentFilter对象的setPriority设置。并且接收者可以终止 传播(调用abortBroadcast()方法即可终止),一旦终止后面接收者就无法接受广播。另外,接受者可以将处理结果存入数据(可通过 setResultExtras(Bundle)方法将数据存入Broadcast),当做Broadcast再传递给下一级接收者(可通过代码 Bundle bundle = getResultExtras(true)获取上一级传递过来的数据)。

 

一、动态广播优先级

②无序广播以并行或者无序方式发送,无优先级

③有序广播按照串行方式发送,有优先级

 

二、静态广播优先级

①无序广播并行或者无序发送

②有序广播串行方式执行,如果是同等优先级,按照app安装的先后执行,因为静态广播注册到系统中,由PMS管理。

 

三、静态广播与动态广播的优先级

①对于无序广播,动态广播优先发送

②对于有序广播,动态广播和静态广播按照优先级合并之后发送,此外,如果优先级相同(算法决定),那么依然是动态态广播先接收

 

四、核心源码分析

ActivityManager.java

  // Figure out who all will receive this broadcast.         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 == Process.SHELL_UID) {                 // Query one target user at a time, excluding shell-restricted users                 UserManagerService ums = getUserManagerLocked();                 for (int i = 0; i < users.length; i++) {                     if (ums.hasUserRestriction(                             UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {                         continue;                     }                     List<BroadcastFilter> registeredReceiversForUser =                             mReceiverResolver.queryIntent(intent,                                     resolvedType, false, users[i]);                     if (registeredReceivers == null) {                         registeredReceivers = registeredReceiversForUser;                     } else if (registeredReceiversForUser != null) {                         registeredReceivers.addAll(registeredReceiversForUser);                     }                 }             } else {                 registeredReceivers = mReceiverResolver.queryIntent(intent,                         resolvedType, false, userId);             }         }          final boolean replacePending =                 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;                  if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueing broadcast: " + intent.getAction()                 + " replacePending=" + replacePending);                  int NR = registeredReceivers != null ? registeredReceivers.size() : 0;         if (!ordered && NR > 0) {             // If we are not serializing this broadcast, then send the             // registered receivers separately so they don't wait for the             // components to be launched.             final BroadcastQueue queue = broadcastQueueForIntent(intent);             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,                     callerPackage, callingPid, callingUid, resolvedType, requiredPermission,                     appOp, registeredReceivers, resultTo, resultCode, resultData, map,                     ordered, sticky, false, userId);             if (DEBUG_BROADCAST) Slog.v(                     TAG, "Enqueueing parallel broadcast " + r);             final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);             if (!replaced) {                 queue.enqueueParallelBroadcastLocked(r);                 queue.scheduleBroadcastsLocked();             }             registeredReceivers = null;             NR = 0;         }          // Merge into one list.         int ir = 0;         if (receivers != null) {             // A special case for PACKAGE_ADDED: do not allow the package             // being added to see this broadcast.  This prevents them from             // using this as a back door to get run as soon as they are             // installed.  Maybe in the future we want to have a special install             // broadcast or such for apps, but we'd like to deliberately make             // this decision.             String skipPackages[] = null;             if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())                     || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())                     || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {                 Uri data = intent.getData();                 if (data != null) {                     String pkgName = data.getSchemeSpecificPart();                     if (pkgName != null) {                         skipPackages = new String[] { pkgName };                     }                 }             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {                 skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);             }             if (skipPackages != null && (skipPackages.length > 0)) {                 for (String skipPackage : skipPackages) {                     if (skipPackage != null) {                         int NT = receivers.size();                         for (int it=0; it<NT; it++) {                             ResolveInfo curt = (ResolveInfo)receivers.get(it);                             if (curt.activityInfo.packageName.equals(skipPackage)) {                                 receivers.remove(it);                                 it--;                                 NT--;                             }                         }                     }                 }             }              int NT = receivers != null ? receivers.size() : 0;             int it = 0;             ResolveInfo curt = null;             BroadcastFilter curr = null;             while (it < NT && ir < NR) {                 if (curt == null) {                     curt = (ResolveInfo)receivers.get(it);                 }                 if (curr == null) {                     curr = registeredReceivers.get(ir);                 }                 if (curr.getPriority() >= curt.priority) {                     // 优先级相同,把动态插入到静态前面                     receivers.add(it, curr);                     ir++;                     curr = null;                     it++;                     NT++;                 } else {                     // Skip to the next ResolveInfo in the final list.                     it++;                     curt = null;                 }             }         }         while (ir < NR) {             if (receivers == null) {                 receivers = new ArrayList();             }             receivers.add(registeredReceivers.get(ir));             ir++;         }          if ((receivers != null && receivers.size() > 0)                 || resultTo != null) {             BroadcastQueue queue = broadcastQueueForIntent(intent);             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,                     callerPackage, callingPid, callingUid, resolvedType,                     requiredPermission, appOp, receivers, resultTo, resultCode,                     resultData, map, ordered, sticky, false, userId);             if (DEBUG_BROADCAST) Slog.v(                     TAG, "Enqueueing ordered broadcast " + r                     + ": prev had " + queue.mOrderedBroadcasts.size());             if (DEBUG_BROADCAST) {                 int seq = r.intent.getIntExtra("seq", -1);                 Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);             }             boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);              if (!replaced) {                 queue.enqueueOrderedBroadcastLocked(r);                 queue.scheduleBroadcastsLocked();             }         }          return ActivityManager.BROADCAST_SUCCESS;

 

 

 

本文发表于2018年01月21日 08:32
(c)注:本文转载自https://my.oschina.net/ososchina/blog/1610161,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1721 讨论 0 喜欢 2

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1