我们在Android应尽量避免使用隐式Intent广播传递信息,为什么这么说?原因有下面几点:

  1. 意外接收:如果同时维护几个项目,不同项目中难免会存在代码复用的情况,这时若安装了两个注册过同样 Action 广播的APP,一个APP通过Context.sendBroadcast()发送的隐式广播也会被另一个APP接收到,并进行相应的操作,可能会产生意想不到的风险。
  2. 敏感信息外泄:发送的隐式广播,可能会被恶意应用注册监听该广播的 receiver 获取到Intent中传递的敏感信息,并进行其他危险的操作。
  3. Intent拦截:如果发送的广播为使用Context.sendOrderedBroadcast()方法发送的有序广播,优先级较高的恶意 receiver 若直接丢弃该广播,会导致服务无法正常使用,或者广播结果被填充恶意数据。

基于以上的几点,会发现使用隐式Intent广播风险很高,那么怎么解决这个问题呢?首先,我们需要明确广播是否仅限于应用内使用。若需要在应用间传递广播,应尽量避免传递敏感信息;否则,可以使用LocalBroadcastManager.sendBroadcast()实现,这样就避免了意外接收广播,敏感信息外泄和Intent拦截的风险

使用方式

SimpleReceiver

  1. class SimpleReceiver : BroadcastReceiver() {
  2. override fun onReceive(context: Context?, intent: Intent?) {
  3. println(" >>>>> SimpleReceiver -> onReceive <<<<< ")
  4. println(" >>>>> ${Thread.currentThread().name} <<<<<")
  5. }
  6. }

ReceiverActivity

  1. class ReceiverActivity : AppCompatActivity() {
  2. val manager: LocalBroadcastManager by lazy {
  3. LocalBroadcastManager.getInstance(this)
  4. }
  5. val receiver: SimpleReceiver by lazy {
  6. SimpleReceiver()
  7. }
  8. val filter: IntentFilter by lazy {
  9. IntentFilter().apply {
  10. addAction("haha")
  11. }
  12. }
  13. override fun onCreate(savedInstanceState: Bundle?) {
  14. super.onCreate(savedInstanceState)
  15. setContentView(R.layout.activity_receiver)
  16. manager.registerReceiver(receiver, filter)
  17. manager.sendBroadcast(Intent("haha"))
  18. }
  19. override fun onDestroy() {
  20. super.onDestroy()
  21. manager.unregisterReceiver(receiver)
  22. }
  23. }

输出信息

  1. ... I/System.out: >>>>> SimpleReceiver -> onReceive <<<<<
  2. ... I/System.out: >>>>> main <<<<<

原码解析

属性

  1. // 记录 Receiver 对应的 ReceiverRecord
  2. private final HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceivers = new HashMap<>();
  3. // 记录 Action 对应的 ReceiverRecord
  4. private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
  5. // 记录 Receiver 消息队列
  6. private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>();

ReceiverRecord 记录 receiver 和 filter

  1. private static final class ReceiverRecord {
  2. final IntentFilter filter;
  3. final BroadcastReceiver receiver;
  4. boolean broadcasting;
  5. boolean dead;
  6. ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {
  7. filter = _filter;
  8. receiver = _receiver;
  9. }
  10. @Override
  11. public String toString() {
  12. StringBuilder builder = new StringBuilder(128);
  13. builder.append("Receiver{");
  14. builder.append(receiver);
  15. builder.append(" filter=");
  16. builder.append(filter);
  17. if (dead) {
  18. builder.append(" DEAD");
  19. }
  20. builder.append("}");
  21. return builder.toString();
  22. }
  23. }

用于记录注册的 receiver 和 对应的 filter

  1. /**
  2. * Register a receive for any local broadcasts that match the given IntentFilter.
  3. * 为任何匹配给定IntentFilter的本地广播注册一个receive
  4. *
  5. * @param receiver The BroadcastReceiver to handle the broadcast.
  6. * 处理广播的广播接收器
  7. *
  8. * @param filter Selects the Intent broadcasts to be received.
  9. * 选择要接收的意图广播
  10. *
  11. * @see #unregisterReceiver
  12. */
  13. public void registerReceiver(@NonNull BroadcastReceiver receiver,
  14. @NonNull IntentFilter filter) {
  15. synchronized (mReceivers) {
  16. ReceiverRecord entry = new ReceiverRecord(filter, receiver);
  17. // 添加 receiver 到 mReceivers
  18. ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
  19. if (filters == null) {
  20. filters = new ArrayList<>(1);
  21. mReceivers.put(receiver, filters);
  22. }
  23. filters.add(entry);
  24. // 记录 filter 包含的所有 action
  25. for (int i=0; i<filter.countActions(); i++) {
  26. String action = filter.getAction(i);
  27. ArrayList<ReceiverRecord> entries = mActions.get(action);
  28. if (entries == null) {
  29. entries = new ArrayList<ReceiverRecord>(1);
  30. mActions.put(action, entries);
  31. }
  32. entries.add(entry);
  33. }
  34. }
  35. }

BroadcastRecord 记录 intent 和 receivers

  1. private static final class BroadcastRecord {
  2. final Intent intent;
  3. final ArrayList<ReceiverRecord> receivers;
  4. BroadcastRecord(Intent _intent, ArrayList<ReceiverRecord> _receivers) {
  5. intent = _intent;
  6. receivers = _receivers;
  7. }
  8. }

匹配 intent 里的 action 对应的 receiver, 用于添加到 mPendingBroadcasts 消息队列用于发送

  1. /**
  2. * Broadcast the given intent to all interested BroadcastReceivers. This
  3. * call is asynchronous; it returns immediately, and you will continue
  4. * executing while the receivers are run.
  5. * 将给定的意图广播给所有感兴趣(匹配)的广播接收器, 这个调用是异步的.
  6. * 它立即返回,并且在运行接收器时您将继续执行
  7. *
  8. * @param intent The Intent to broadcast; all receivers matching this
  9. * Intent will receive the broadcast.
  10. * 所有符合此意图的接收器将接收广播
  11. *
  12. * @see #registerReceiver
  13. *
  14. * @return Returns true if the intent has been scheduled for delivery to one or more
  15. * broadcast receivers. (Note tha delivery may not ultimately take place if one of those
  16. * receivers is unregistered before it is dispatched.)
  17. * 如果意图已被安排交付给一个或多个广播接收器,则返回true(请注意,
  18. * 如果其中一个接收方在发送前未注册,则该交付可能不会最终发生)
  19. */
  20. public boolean sendBroadcast(@NonNull Intent intent) {
  21. synchronized (mReceivers) {
  22. final String action = intent.getAction();
  23. final String type = intent.resolveTypeIfNeeded(
  24. mAppContext.getContentResolver());
  25. final Uri data = intent.getData();
  26. final String scheme = intent.getScheme();
  27. final Set<String> categories = intent.getCategories();
  28. final boolean debug = DEBUG ||
  29. ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
  30. if (debug) Log.v(
  31. TAG, "Resolving type " + type + " scheme " + scheme
  32. + " of intent " + intent);
  33. // 获取 action 对应的 ReceiverRecord 集合
  34. ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
  35. if (entries != null) {
  36. if (debug) Log.v(TAG, "Action list: " + entries);
  37. ArrayList<ReceiverRecord> receivers = null;
  38. for (int i=0; i<entries.size(); i++) {
  39. ReceiverRecord receiver = entries.get(i);
  40. if (debug) Log.v(TAG, "Matching against filter " + receiver.filter);
  41. if (receiver.broadcasting) {
  42. if (debug) {
  43. Log.v(TAG, " Filter's target already added");
  44. }
  45. continue;
  46. }
  47. int match = receiver.filter.match(action, type, scheme, data,
  48. categories, "LocalBroadcastManager");
  49. if (match >= 0) {
  50. if (debug) Log.v(TAG, " Filter matched! match=0x" +
  51. Integer.toHexString(match));
  52. if (receivers == null) {
  53. receivers = new ArrayList<ReceiverRecord>();
  54. }
  55. receivers.add(receiver);
  56. receiver.broadcasting = true;
  57. } else {
  58. if (debug) {
  59. String reason;
  60. switch (match) {
  61. case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
  62. case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
  63. case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
  64. case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
  65. default: reason = "unknown reason"; break;
  66. }
  67. Log.v(TAG, " Filter did not match: " + reason);
  68. }
  69. }
  70. }
  71. if (receivers != null) {
  72. for (int i=0; i<receivers.size(); i++) {
  73. receivers.get(i).broadcasting = false;
  74. }
  75. mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
  76. if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
  77. mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
  78. }
  79. return true;
  80. }
  81. }
  82. }
  83. return false;
  84. }

通过 handler 处理消息队列 mPendingBroadcasts

  1. private LocalBroadcastManager(Context context) {
  2. mAppContext = context;
  3. mHandler = new Handler(context.getMainLooper()) {
  4. @Override
  5. public void handleMessage(Message msg) {
  6. switch (msg.what) {
  7. case MSG_EXEC_PENDING_BROADCASTS:
  8. executePendingBroadcasts();
  9. break;
  10. default:
  11. super.handleMessage(msg);
  12. }
  13. }
  14. };
  15. }
  16. void executePendingBroadcasts() {
  17. while (true) {
  18. final BroadcastRecord[] brs;
  19. synchronized (mReceivers) {
  20. final int N = mPendingBroadcasts.size();
  21. if (N <= 0) {
  22. return;
  23. }
  24. brs = new BroadcastRecord[N];
  25. mPendingBroadcasts.toArray(brs);
  26. mPendingBroadcasts.clear();
  27. }
  28. for (int i=0; i<brs.length; i++) {
  29. final BroadcastRecord br = brs[i];
  30. final int nbr = br.receivers.size();
  31. for (int j=0; j<nbr; j++) {
  32. final ReceiverRecord rec = br.receivers.get(j);
  33. if (!rec.dead) {
  34. rec.receiver.onReceive(mAppContext, br.intent);
  35. }
  36. }
  37. }
  38. }
  39. }