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

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


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

[html]  view plain copy 在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 plain copy 在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 plain copy 在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 plain copy 在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 plain copy 在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 plain copy 在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这个组件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值