Android广播机制实现源码浅析(三)

转载 2015年04月18日 13:35:03

http://blog.csdn.net/hehui1860/article/details/30727537


在上篇的分析的最后,我们留下了两个问题,一个是静态广播以及有序广播的处理过程,还有一个就是提过的广播超时机制。
在本篇中将对这两个问题进行一一的阐述:
(1)静态广播以及有序广播的处理过程:
从前面的流程中可以看出,静态注册的广播统一的存在了变量mOrderedBroadcasts中,也就是说静态广播在服务中都是作为有序广播来处理的。但是发送有序广播时,动态和静态的广播接收器都是保存在这里进行分发的,所以以下对mOrderedBroadcasts的处理就包含了两个分支的处理,来看看源码

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. final void processNextBroadcast(boolean fromMsg) {  
  2. ............  
  3.  do {  
  4.                 if (mOrderedBroadcasts.size() == 0) {  
  5.                       ..............  
  6.                      return;  
  7.                 }  
  8.                 r = mOrderedBroadcasts.get(0);  
  9.                 boolean forceReceive = false;  
  10.                 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;  
  11.                 if (mService.mProcessesReady && r.dispatchTime > 0) {  
  12.                     long now = SystemClock.uptimeMillis();  
  13.                     if ((numReceivers > 0) &&  
  14.                             (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {  
  15.                         Slog.w(TAG, "Hung broadcast ["  
  16.                                 + mQueueName + "] discarded after timeout failure:"  
  17.                                 + " now=" + now  
  18.                                 + " dispatchTime=" + r.dispatchTime  
  19.                                 + " startTime=" + r.receiverTime  
  20.                                 + " intent=" + r.intent  
  21.                                 + " numReceivers=" + numReceivers  
  22.                                 + " nextReceiver=" + r.nextReceiver  
  23.                                 + " state=" + r.state);  
  24.                         //设置系统处理广播的总时长,与接收器的个数有关  
  25.                         broadcastTimeoutLocked(false); // forcibly finish this broadcast  
  26.                         forceReceive = true;  
  27.                         r.state = BroadcastRecord.IDLE;  
  28.                     }  
  29.                 }  
  30.                 if (r.receivers == null || r.nextReceiver >= numReceivers  
  31.                         || r.resultAbort || forceReceive) {  
  32.                     // No more receivers for this broadcast!  Send the final  
  33.                     // result if requested...  
  34.                     if (r.resultTo != null) {  
  35.                         try {  
  36.                             if (DEBUG_BROADCAST) {  
  37.                                 int seq = r.intent.getIntExtra("seq", -1);  
  38.                                 Slog.i(TAG, "Finishing broadcast ["  
  39.                                         + mQueueName + "] " + r.intent.getAction()  
  40.                                         + " seq=" + seq + " app=" + r.callerApp);  
  41.                             }  
  42.                             performReceiveLocked(r.callerApp, r.resultTo,  
  43.                                 new Intent(r.intent), r.resultCode,  
  44.                                 r.resultData, r.resultExtras, false, false, r.userId);  
  45.                             // Set this to null so that the reference  
  46.                             // (local and remote) isnt kept in the mBroadcastHistory.  
  47.                             r.resultTo = null;  
  48.                         } catch (RemoteException e) {  
  49.                             Slog.w(TAG, "Failure ["  
  50.                                     + mQueueName + "] sending broadcast result of "  
  51.                                     + r.intent, e);  
  52.                         }  
  53.                     }  
  54.   
  55.                     if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");  
  56.                     //处理完毕时会清除超时的设置  
  57.                     cancelBroadcastTimeoutLocked();  
  58.   
  59.                     if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "  
  60.                             + r);  
  61.   
  62.                     // ... and on to the next...  
  63.                     addBroadcastToHistoryLocked(r);  
  64.                     mOrderedBroadcasts.remove(0);  
  65.                     r = null;  
  66.                     looped = true;  
  67.                     continue;  
  68.                 }  
  69.   
  70.        }  
  71. ............  
  72. if (! mPendingBroadcastTimeoutMessage) {  
  73.                 long timeoutTime = r.receiverTime + mTimeoutPeriod;  
  74.                 if (DEBUG_BROADCAST) Slog.v(TAG,  
  75.                         "Submitting BROADCAST_TIMEOUT_MSG ["  
  76.                         + mQueueName + "] for " + r + " at " + timeoutTime);  
  77.                 //设置单个接收器的处理超时机制  
  78.                 setBroadcastTimeoutLocked(timeoutTime);  
  79. }  
  80. .................  
  81. Object nextReceiver = r.receivers.get(recIdx);  
  82.  if (nextReceiver instanceof BroadcastFilter) {  
  83.                 ..............  
  84.          deliverToRegisteredReceiverLocked(r, filter, r.ordered);  
  85.          return;  
  86. }  
  87. ResolveInfo info =(ResolveInfo)nextReceiver;  
  88. ComponentName component = new ComponentName(  
  89. info.activityInfo.applicationInfo.packageName,  
  90.                     info.activityInfo.name);  
  91.            ................  
  92.            // Broadcast is being executed, its package can't be stopped.  
  93.             try {  
  94.                 AppGlobals.getPackageManager().setPackageStoppedState(  
  95.                         r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));  
  96.             } catch (RemoteException e) {  
  97.             } catch (IllegalArgumentException e) {  
  98.                 Slog.w(TAG, "Failed trying to unstop package "  
  99.                         + r.curComponent.getPackageName() + ": " + e);  
  100.             }  
  101.   
  102.            // Is this receiver's application already running?  
  103.             ProcessRecord app = mService.getProcessRecordLocked(targetProcess,  
  104.                     info.activityInfo.applicationInfo.uid);  
  105.             if (app != null && app.thread != null) {  
  106.                 try {  
  107.                     app.addPackage(info.activityInfo.packageName);  
  108.                     processCurBroadcastLocked(r, app);  
  109.                     return;  
  110.                 } catch (RemoteException e) {  
  111.                     Slog.w(TAG, "Exception when sending broadcast to "  
  112.                           + r.curComponent, e);  
  113.                 }  
  114.   
  115.                 // If a dead object exception was thrown -- fall through to  
  116.                 // restart the application.  
  117.             }  
  118.             // Not running -- get it started, to be executed when the app comes up.  
  119.             if (DEBUG_BROADCAST)  Slog.v(TAG,  
  120.                     "Need to start app ["  
  121.                     + mQueueName + "] " + targetProcess + " for broadcast " + r);  
  122.             if ((r.curApp=mService.startProcessLocked(targetProcess,  
  123.                     info.activityInfo.applicationInfo, true,  
  124.                     r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,  
  125.                     "broadcast", r.curComponent,  
  126.                     (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))  
  127.                             == null) {  
  128.                 // Ah, this recipient is unavailable.  Finish it if necessary,  
  129.                 // and mark the broadcast record as ready for the next.  
  130.                 Slog.w(TAG, "Unable to launch app "  
  131.                         + info.activityInfo.applicationInfo.packageName + "/"  
  132.                         + info.activityInfo.applicationInfo.uid + " for broadcast "  
  133.                         + r.intent + ": process is bad");  
  134.                 logBroadcastReceiverDiscardLocked(r);  
  135.                 finishReceiverLocked(r, r.resultCode, r.resultData,  
  136.                         r.resultExtras, r.resultAbort, true);  
  137.                 scheduleBroadcastsLocked();  
  138.                 r.state = BroadcastRecord.IDLE;  
  139.                 return;  
  140.             }  
  141.   
  142. }  


代码中可以看到,分支判断就是以nextReceiver是继承于BroadcastFilter还是ResolveInfo,前者是动态注册时的产物,后面的处理于前文所述一样,后者是静态注册的信息,后续通过调用processCurBroadcastLocked来实现广播的处理
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private final void processCurBroadcastLocked(BroadcastRecord r,  
  2.             ProcessRecord app) throws RemoteException {  
  3.        try {  
  4.             if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,  
  5.                     "Delivering to component " + r.curComponent  
  6.                     + ": " + r);  
  7.             mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());  
  8.             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,  
  9.                     mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),  
  10.                     r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId);  
  11.             if (DEBUG_BROADCAST)  Slog.v(TAG,  
  12.                     "Process cur broadcast " + r + " DELIVERED for app " + app);  
  13.             started = true;  
  14.         }  
  15. }  


这里用到的几个变量是不是很熟悉,app,app.thread,这里又是一个跨进程调用。实现在activitythread中。
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public final void scheduleReceiver(Intent intent, ActivityInfo info,  
  2.                 CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,  
  3.                 boolean sync, int sendingUser) {  
  4.             ReceiverData r = new ReceiverData(intent, resultCode, data, extras,  
  5.                     sync, false, mAppThread.asBinder(), sendingUser);  
  6.             r.info = info;  
  7.             r.compatInfo = compatInfo;  
  8.             queueOrSendMessage(H.RECEIVER, r);  
  9. }  
  10. private class H extends Handler {  
  11.                 ...............  
  12.                 case RECEIVER:  
  13.                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");  
  14.                     handleReceiver((ReceiverData)msg.obj);  
  15.                     maybeSnapshot();  
  16.                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);  
  17.                     break;  
  18.                 ...............  
  19. }  
  20.     private void handleReceiver(ReceiverData data) {  
  21.         // If we are getting ready to gc after going to the background, well  
  22.         // we are back active so skip it.  
  23.         unscheduleGcIdler();  
  24.   
  25.         String component = data.intent.getComponent().getClassName();  
  26.   
  27.         LoadedApk packageInfo = getPackageInfoNoCheck(  
  28.                 data.info.applicationInfo, data.compatInfo);  
  29.   
  30.         IActivityManager mgr = ActivityManagerNative.getDefault();  
  31.   
  32.         BroadcastReceiver receiver;  
  33.         try {  
  34.             java.lang.ClassLoader cl = packageInfo.getClassLoader();  
  35.             data.intent.setExtrasClassLoader(cl);  
  36.             data.setExtrasClassLoader(cl);  
  37.             receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();  
  38.         } catch (Exception e) {  
  39.             if (DEBUG_BROADCAST) Slog.i(TAG,  
  40.                     "Finishing failed broadcast to " + data.intent.getComponent());  
  41.             data.sendFinished(mgr);  
  42.             throw new RuntimeException(  
  43.                 "Unable to instantiate receiver " + component  
  44.                 + ": " + e.toString(), e);  
  45.         }  
  46.   
  47.         try {  
  48.             Application app = packageInfo.makeApplication(false, mInstrumentation);  
  49.   
  50.             if (localLOGV) Slog.v(  
  51.                 TAG, "Performing receive of " + data.intent  
  52.                 + ": app=" + app  
  53.                 + ", appName=" + app.getPackageName()  
  54.                 + ", pkg=" + packageInfo.getPackageName()  
  55.                 + ", comp=" + data.intent.getComponent().toShortString()  
  56.                 + ", dir=" + packageInfo.getAppDir());  
  57.   
  58.             ContextImpl context = (ContextImpl)app.getBaseContext();  
  59.             sCurrentBroadcastIntent.set(data.intent);  
  60.             receiver.setPendingResult(data);  
  61.             receiver.onReceive(context.getReceiverRestrictedContext(),  
  62.                     data.intent);  
  63.         } catch (Exception e) {  
  64.             if (DEBUG_BROADCAST) Slog.i(TAG,  
  65.                     "Finishing failed broadcast to " + data.intent.getComponent());  
  66.             data.sendFinished(mgr);  
  67.             if (!mInstrumentation.onException(receiver, e)) {  
  68.                 throw new RuntimeException(  
  69.                     "Unable to start receiver " + component  
  70.                     + ": " + e.toString(), e);  
  71.             }  
  72.         } finally {  
  73.             sCurrentBroadcastIntent.set(null);  
  74.         }  
  75.   
  76.         if (receiver.getPendingResult() != null) {  
  77.             data.finish();  
  78.         }  
  79.     }  


到这里调用 receiver.onReceive(context.getReceiverRestrictedContext(), data.intent);已经完成了应用广播的处理。接下来还有一个非常重要的操作,就是结束,因为有序广播是串行执行的,所以一个处理完需要触发下一个的处理。
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public final void finish() {  
  2.     if (mType == TYPE_COMPONENT) {  
  3.         final IActivityManager mgr = ActivityManagerNative.getDefault();  
  4.         if (QueuedWork.hasPendingWork()) {  
  5.             // If this is a broadcast component, we need to make sure any  
  6.             // queued work is complete before telling AM we are done, so  
  7.             // we don't have our process killed before that.  We now know  
  8.             // there is pending work; put another piece of work at the end  
  9.             // of the list to finish the broadcast, so we don't block this  
  10.             // thread (which may be the main thread) to have it finished.  
  11.             //  
  12.             // Note that we don't need to use QueuedWork.add() with the  
  13.             // runnable, since we know the AM is waiting for us until the  
  14.             // executor gets to it.  
  15.             QueuedWork.singleThreadExecutor().execute( new Runnable() {  
  16.                 @Override public void run() {  
  17.                     if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,  
  18.                             "Finishing broadcast after work to component " + mToken);  
  19.                     sendFinished(mgr);  
  20.                 }  
  21.             });  
  22.         } else {  
  23.             if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,  
  24.                     "Finishing broadcast to component " + mToken);  
  25.             sendFinished(mgr);  
  26.         }  
  27.     } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {  
  28.         if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,  
  29.                 "Finishing broadcast to " + mToken);  
  30.         final IActivityManager mgr = ActivityManagerNative.getDefault();  
  31.         sendFinished(mgr);  
  32.     }  
  33. }  
  34. public void sendFinished(IActivityManager am) {  
  35.     synchronized (this) {  
  36.         if (mFinished) {  
  37.             throw new IllegalStateException("Broadcast already finished");  
  38.         }  
  39.         mFinished = true;  
  40.       
  41.         try {  
  42.             if (mResultExtras != null) {  
  43.                 mResultExtras.setAllowFds(false);  
  44.             }  
  45.             if (mOrderedHint) {  
  46.                 am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,  
  47.                         mAbortBroadcast);  
  48.             } else {  
  49.                 // This broadcast was sent to a component; it is not ordered,  
  50.                 // but we still need to tell the activity manager we are done.  
  51.                 am.finishReceiver(mToken, 0, null, null, false);  
  52.             }  
  53.         } catch (RemoteException ex) {  
  54.         }  
  55.     }  
  56. }  


看这里的finish操作又回去了,回到了ActivityManagerService中,继续看
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void finishReceiver(IBinder who, int resultCode, String resultData,  
  2.             Bundle resultExtras, boolean resultAbort) {  
  3.         if (DEBUG_BROADCAST) Slog.v(TAG, "Finish receiver: " + who);  
  4.   
  5.         // Refuse possible leaked file descriptors  
  6.         if (resultExtras != null && resultExtras.hasFileDescriptors()) {  
  7.             throw new IllegalArgumentException("File descriptors passed in Bundle");  
  8.         }  
  9.   
  10.         final long origId = Binder.clearCallingIdentity();  
  11.         try {  
  12.             boolean doNext = false;  
  13.             BroadcastRecord r = null;  
  14.   
  15.             synchronized(this) {  
  16.                 r = broadcastRecordForReceiverLocked(who);  
  17.                 if (r != null) {  
  18.                     doNext = r.queue.finishReceiverLocked(r, resultCode,  
  19.                         resultData, resultExtras, resultAbort, true);  
  20.                 }  
  21.             }  
  22.   
  23.             if (doNext) {  
  24.                 r.queue.processNextBroadcast(false);  
  25.             }  
  26.             trimApplications();  
  27.         } finally {  
  28.             Binder.restoreCallingIdentity(origId);  
  29.         }  
  30.     }  


是不是又看到了熟悉的一个方法了,对了,结束后又开始处理下一个了。
(2)广播超时机制
下面开始说第二个问题,超时,相信大家在前面的代码中已经看到了关于超时的代码描述。没错,只有在处理有序广播时才有这个概念的出现,它有两个含义,一个是广播处理的总时间,还有一个是每个onReceiver的处理时间。到时间就会进行ANR处理了。
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. final void broadcastTimeoutLocked(boolean fromMsg) {  
  2.         .............  
  3.         if (anrMessage != null) {  
  4.             // Post the ANR to the handler since we do not want to process ANRs while  
  5.             // potentially holding our lock.  
  6.             mHandler.post(new AppNotResponding(app, anrMessage));  
  7.         }  
  8. }  


下面给大家推荐一篇分析广播机制的博客:http://blog.csdn.net/windskier/article/details/7251742
看完以上的流程分析之后适合看这篇日志梳理一下脉络并从一个较高的高度来看待BroadcastReciver这个组件

相关文章推荐

bug系列-------home界面自动刷新

最近遇到一个bug,setting里将display设置为never sleep之后返回home界面,系统会不断刷新,看了一下log发现下面一段有问题 09-20 03:41:42.013  597...

Android : Broadcast

Broadcast是Application之间交换数据最简单的一种方法。Broadcast组成部分Broadcast 功能,由发送Broadcast的Sender和接收的Receiver组成。 Se...

Android 源码系列之<三>从安全的角度深入理解BroadcastReceiver(下)

在上一篇文章中我们结合实验讲解了有关使用BroadcastReceiver存在的安全性问题并且给出了相应的解决方案,如果你还没有看过上篇文章请点击这里,最后一条的解决方案是采用官方v4包中的Local...

BroadcastReceiver源码解析(一)

1,简介BroadcastReceiver,中文直译为“广播接收者”,在Android 系统中,广播主要用在组件与组件之间进行消息传递。组件与组件之间可以是同一个进程,也可以是不同进程。既然是可以跨进...

Android Broadcast timeout

Broadcast timeout Brocadcast timeout 是指串行有序广播发送给receiver的时候,app没有来得及处理这个广播,或者app的receiver处理这个广播的时候超...
  • miaotao
  • miaotao
  • 2017年04月20日 15:30
  • 768

Android——Activity、Service、Broadcast,超时时间报ANR

Activity----->5秒 Broadcast----->10秒 Service----->20秒 会报ANR,都是在主线程中运行的...

android 解决广播接收延时问题:前台广播

android 解决广播接收延时问题:前台广播 。   Intent mIntent = new Intent("android.i...

Android系统中的广播(Broadcast)机制简要介绍和学习计划

在Android系统中,广播(Broadcast)是在组件之间传播数据(Intent)的一种机制;这些组件甚至是可以位于不同的进程中,这样它就像Binder机制一样,起到进程间通信的作用;本文通过一个...

Android Broadcast广播机制分析

基于Android 6.0的源码剖析, 分析android广播的发送与接收流程。 一、概述 广播(Broadcast)机制用于进程/线程间通信,广播分为广播发送和广播接收两个过程,其中...

universal-image-loader-1.9.3的简单使用,异步加载图片

import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.F...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android广播机制实现源码浅析(三)
举报原因:
原因补充:

(最多只允许输入30个字)