[关闭]
@linux1s1s 2017-01-22T08:17:04.000000Z 字数 4108 阅读 1991

Android BroadCast (二)

AndroidComponent 2015-06


Android BroadCast (一) 揭开了关于BroadCast网络上普遍的误解,这里进一步对BroadCast发送的两种方式做基本的介绍:

Application"广域网"广播

先看代码:

  1. getActivity().sendBroadcast(new Intent("Action"));

假如这个是在Fragment中的一处代码,我们顺着这个代码跟踪下去:

ContextWrapper.java

  1. @Override
  2. public void sendBroadcast(Intent intent) {
  3. mBase .sendBroadcast( intent);
  4. }

我们接着往下看, sendBroadcast到底干神马了?
接着进入 Context类的抽象方法:

  1. public abstract void sendBroadcast(Intent intent);

所以找一下实现方法:比较多,这里重点看一下:ContextImpl这个类的具体实现:

  1. @Override
  2. public void sendBroadcast(Intent intent) {
  3. warnIfCallingFromSystemProcess();
  4. String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
  5. try {
  6. intent.prepareToLeaveProcess();
  7. ActivityManagerNative.getDefault().broadcastIntent(
  8. mMainThread.getApplicationThread(), intent, resolvedType, null,
  9. Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
  10. getUserId());
  11. } catch (RemoteException e) {
  12. }
  13. }

最后调用了ActivityManagerNative.getDefault().broadcastIntent(...) 跟着这个方法继续往下看:
进入到ActviityManagerService类,这个是典型的Android Service 类:

  1. public final int broadcastIntent(IApplicationThread caller,
  2. Intent intent, String resolvedType, IIntentReceiver resultTo,
  3. int resultCode, String resultData, Bundle map,
  4. String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
  5. enforceNotIsolatedCaller("broadcastIntent");
  6. synchronized(this) {
  7. intent = verifyBroadcastLocked(intent);
  8. final ProcessRecord callerApp = getRecordForAppLocked(caller);
  9. final int callingPid = Binder.getCallingPid();
  10. final int callingUid = Binder.getCallingUid();
  11. final long origId = Binder.clearCallingIdentity();
  12. int res = broadcastIntentLocked(callerApp,
  13. callerApp != null ? callerApp.info.packageName : null,
  14. intent, resolvedType, resultTo,
  15. resultCode, resultData, map, requiredPermission, appOp, serialized, sticky,
  16. callingPid, callingUid, userId);
  17. Binder.restoreCallingIdentity(origId);
  18. return res;
  19. }
  20. }

看到这里 不打算往下追代码了:本质上可以理解为: App进程发送广播到系统的Service,然后系统的Service转发给所有正在运行的进程。当这些进程接受到广播后,看一下自己是否注册了这个广播,如果需要这个信息,那么就会根据这个信息在各自的onReceive()方法中作出响应,这样一个过程像不像是广域网发送广播的情况(当然真实的网络通信是不可能在广域网发送广播的,如果一个请求,每次都要向互联网的所有网络都发送请求,那将是一个灾难。这里为了说明情况,只是打个比方,理解一下就可以了。)

Application"局域网"广播

有很多APP不想让其他App接收到自己发出去的广播,大部分有这些需求的都是出于安全考虑,那么该如何避免"广域网"广播呢?

很简单,Android 为我们提供了一个比较方便的类:LocalBroadcastManager类,所以这个时候想发送比较安全的广播,应该这么做:

  1. LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(new Intent("Action"));

往下追踪一下代码,看看是如何做到的?

  1. public boolean sendBroadcast(Intent intent) {
  2. synchronized (mReceivers) {
  3. final String action = intent.getAction();
  4. final String type = intent.resolveTypeIfNeeded(
  5. mAppContext.getContentResolver());
  6. final Uri data = intent.getData();
  7. final String scheme = intent.getScheme();
  8. final Set<String> categories = intent.getCategories();
  9. final boolean debug = DEBUG ||
  10. ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
  11. if (debug) Log.v(
  12. TAG, "Resolving type " + type + " scheme " + scheme
  13. + " of intent " + intent);
  14. ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
  15. if (entries != null) {
  16. if (debug) Log.v(TAG, "Action list: " + entries);
  17. ArrayList<ReceiverRecord> receivers = null;
  18. for (int i=0; i<entries.size(); i++) {
  19. ReceiverRecord receiver = entries.get(i);
  20. if (debug) Log.v(TAG, "Matching against filter " + receiver.filter);
  21. if (receiver.broadcasting) {
  22. if (debug) {
  23. Log.v(TAG, " Filter's target already added");
  24. }
  25. continue;
  26. }
  27. int match = receiver.filter.match(action, type, scheme, data,
  28. categories, "LocalBroadcastManager");
  29. if (match >= 0) {
  30. if (debug) Log.v(TAG, " Filter matched! match=0x" +
  31. Integer.toHexString(match));
  32. if (receivers == null) {
  33. receivers = new ArrayList<ReceiverRecord>();
  34. }
  35. receivers.add(receiver);
  36. receiver.broadcasting = true;
  37. } else {
  38. if (debug) {
  39. String reason;
  40. switch (match) {
  41. case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
  42. case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
  43. case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
  44. case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
  45. default: reason = "unknown reason"; break;
  46. }
  47. Log.v(TAG, " Filter did not match: " + reason);
  48. }
  49. }
  50. }
  51. if (receivers != null) {
  52. for (int i=0; i<receivers.size(); i++) {
  53. receivers.get(i).broadcasting = false;
  54. }
  55. mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
  56. if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
  57. mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
  58. }
  59. return true;
  60. }
  61. }
  62. }
  63. return false;
  64. }

我们可以发现,其实是对Receiver做了一定的筛选以后,再发送广播的,所以仅仅是在App所在的进程中才会接收到广播,就像是网络通信中的局域网广播一样,这样就有效避免的不怀好意的Receive做非法监听了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注