多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > Android廣播發送機制剖析【android廣播系列二】

Android廣播發送機制剖析【android廣播系列二】

來源:程序員人生   發布時間:2015-05-06 08:39:39 閱讀次數:4462次
   上篇博客大致說了說廣播的注冊機制,動態注冊和靜態注冊廣播的原理還不1樣,動態廣播最后HashMap中了,最后放到mReceiverResolver中,
   以后當ActivityManagerService接收到廣播的時候,它就能夠再成員變量mReceiverResolver中找到對應的廣播接收者了。下面我們來講說廣播的發送機制。
   廣播發送時候,在Context.java的方法中調用的,有以下方法:
   sendBroadcast(Intent intent) ;
   sendBroadcast(Intent intent, String receiverPermission) 
   sendBroadcastAsUser(Intent intent, UserHandle user) 
   sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission)
   sendOrderedBroadcast(Intent intent, String receiverPermission)
   sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) 
   sendStickyBroadcast(Intent intent) 
   sendStickyBroadcastAsUser(Intent intent, UserHandle user) 
   sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) 
   sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) 
  以上就是發送廣播的方式,但是經常使用的就幾種,其中比較經常使用的就是sendBroadcast(Intent intent) ;我就說下這類發送廣播的方式。

發送廣播的大致流程

Step1:sendBroadcast()方法開始

sendBroadcast在context中調用的,往下調用到了ContextImpl.java中去了:

/** * Common implementation of Context API, which provides the base * context object for Activity and other application components. */ class ContextImpl extends Context { private final static String TAG = "ContextImpl"; private final static boolean DEBUG = false;
@Override public void sendBroadcast(Intent intent, String receiverPermission) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, false, false, getUserId()); } catch (RemoteException e) { } }

Step2:調用到broadcastIntent()方法中

調用到了ActivityManagerService.java中的broadcastIntent()方法中去了,

public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo,int resultCode, String resultData, Bundle map, String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) { enforceNotIsolatedCaller("broadcastIntent"); synchronized(this) { //校驗廣播是不是鎖定 intent = verifyBroadcastLocked(intent); final ProcessRecord callerApp = getRecordForAppLocked(caller); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, appOp, serialized, sticky, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; } }

Step3:調用到broadcastIntentLocked()方法中

這個方法有點復雜,邏輯量有點大

private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, int appOp, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { intent = new Intent(intent); // By default broadcasts do not go to stopped apps. 1)如果apk被forceStop()強行停止或安裝后就沒有啟動過,這個apk就處于停 止狀態(stopped state) =============================================================== intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); if (DEBUG_BROADCAST_LIGHT) Slog.v( TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent + " ordered=" + ordered + " userid=" + userId); if ((resultTo != null) && !ordered) { Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!"); } userId = handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_NON_FULL, "broadcast", callerPackage); // Make sure that the user who is receiving this broadcast is started. // If not, we will just skip it. if (userId != UserHandle.USER_ALL && mStartedUsers.get(userId) == null) { if (callingUid != Process.SYSTEM_UID || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0){ Slog.w(TAG, "Skipping broadcast of " + intent + ": user " + userId + " is stopped"); return ActivityManager.BROADCAST_SUCCESS; } } 2)判斷當前是不是有權利發出廣播 =============== /* * Prevent non-system code (defined here to be non-persistent * processes) from sending protected broadcasts. */ int callingAppId = UserHandle.getAppId(callingUid); if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID || callingAppId == Process.NFC_UID || callingUid == 0) { // Always okay. } else if (callerApp == null || !callerApp.persistent) { try { if (AppGlobals.getPackageManager().isProtectedBroadcast( intent.getAction())) { String msg = "Permission Denial: not allowed to send broadcast " + intent.getAction() + " from pid=" + callingPid + ", uid=" + callingUid; Slog.w(TAG, msg); throw new SecurityException(msg); } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) { // Special case for compatibility: we don't want apps to send this, // but historically it has not been protected and apps may be using it // to poke their own app widget. So, instead of making it protected, // just limit it to the caller. if (callerApp == null) { String msg = "Permission Denial: not allowed to send broadcast " + intent.getAction() + " from unknown caller."; Slog.w(TAG, msg); throw new SecurityException(msg); } else if (intent.getComponent() != null) { // They are good enough to send to an explicit component... verify // it is being sent to the calling app. if (!intent.getComponent().getPackageName().equals( callerApp.info.packageName)) { String msg = "Permission Denial: not allowed to send broadcast " + intent.getAction() + " to " +intent.getComponent().getPackageName() + " from "callerApp.info.packageName; Slog.w(TAG, msg); throw new SecurityException(msg); } } else { // Limit broadcast to their own package. intent.setPackage(callerApp.info.packageName); } } } catch (RemoteException e) { Slog.w(TAG, "Remote exception", e); return ActivityManager.BROADCAST_SUCCESS; } } 3)處理和package相干的廣播,如果這個package被卸載了,我們也要相應地移除它所有的組件 ================================================= // Handle special intents: if this broadcast is from the package // manager about a package being removed, we need to remove all of // its activities from the history stack. final boolean uidRemoved = Intent.ACTION_UID_REMOVED.equals( intent.getAction()); if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) || Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction()) || Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction()) || uidRemoved) { if (checkComponentPermission( android.Manifest.permission.BROADCAST_PACKAGE_REMOVED, callingPid, callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) { if (uidRemoved) { final Bundle intentExtras = intent.getExtras(); final int uid = intentExtras != null ? intentExtras.getInt(Intent.EXTRA_UID) : -1; if (uid >= 0) { BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics(); synchronized (bs) { bs.removeUidStatsLocked(uid); } mAppOpsService.uidRemoved(uid); } } else { // If resources are unavailable just force stop all // those packages and flush the attribute cache as well. if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) { String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); if (list != null && (list.length > 0)) { for (String pkg : list) { forceStopPackageLocked(pkg, -1, false, true, true, false, false, userId, "storage unmount"); } cleanupRecentTasksLocked(UserHandle.USER_ALL); sendPackageBroadcastLocked( IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list, userId); } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals( intent.getAction())) { cleanupRecentTasksLocked(UserHandle.USER_ALL); } else { Uri data = intent.getData(); String ssp; if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals( intent.getAction()); boolean fullUninstall = removed && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) { forceStopPackageLocked(ssp, UserHandle.getAppId( intent.getIntExtra(Intent.EXTRA_UID, -1)), false, true, true, false, fullUninstall, userId, removed ? "pkg removed" : "pkg changed"); } if (removed) { sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED, new String[] {ssp}, userId); if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { mAppOpsService.packageRemoved( intent.getIntExtra(Intent.EXTRA_UID, -1), ssp); // Remove all permissions granted from/to this package removeUriPermissionsForPackageLocked(ssp, userId, true); } } } } } } else { String msg = "Permission Denial: " + intent.getAction() + " broadcast from " + callerPackage + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " requires " + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED; Slog.w(TAG, msg); throw new SecurityException(msg); } // Special case for adding a package: by default turn on compatibility // mode. } else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { Uri data = intent.getData(); String ssp; if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { mCompatModePackages.handlePackageAddedLocked(ssp, intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)); } } 4)處理其他1些系統廣播ACTION_TIMEZONE_CHANGED,ACTION_TIME_CHANGED,PROXY_CHANGE_ACTION, ======================================================================== /* * If this is the time zone changed action, queue up a message that will reset the timezone * of all currently running processes. This message will get queued up before the broadcast * happens. */ if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) { mHandler.sendEmptyMessage(UPDATE_TIME_ZONE); } /* * If the user set the time, let all running processes know. */ if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) { final int is24Hour = intent.getBooleanExtra( Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1 : 0; mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0)); BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { stats.noteCurrentTimeChangedLocked(); } } if (Intent.ACTION_CLEAR_DNS_CACHE.equals(intent.getAction())) { mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG); } if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) { ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO); mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy)); } 5)判斷廣播是不是是1個黏性廣播,所有相同類型的黏性廣播保存起到1個列表中,最后會保存到mStickyBroadcasts這個HashMap中。 ====================================== // Add to the sticky list if requested. if (sticky) { if (checkPermission(android.Manifest.permission.BROADCAST_STICKY, callingPid, callingUid) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid=" + callingPid + ", uid=" + callingUid + " requires " + android.Manifest.permission.BROADCAST_STICKY; Slog.w(TAG, msg); throw new SecurityException(msg); } if (requiredPermission != null) { Slog.w(TAG, "Can't broadcast sticky intent " + intent + " and enforce permission " + requiredPermission); return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION; } if (intent.getComponent() != null) { throw new SecurityException( "Sticky broadcasts can't target a specific component"); } // We use userId directly here, since the "all" target is maintained // as a separate set of sticky broadcasts. if (userId != UserHandle.USER_ALL) { // But first, if this is not a broadcast to all users, then // make sure it doesn't conflict with an existing broadcast to // all users. ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get( UserHandle.USER_ALL); if (stickies != null) { ArrayList<Intent> list = stickies.get(intent.getAction()); if (list != null) { int N = list.size(); int i; for (i=0; i<N; i++) { if (intent.filterEquals(list.get(i))) { throw new IllegalArgumentException( "Sticky broadcast " + intent + " for user " + userId + " conflicts with existing global broadcast"); } } } } } ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies == null) { stickies = new ArrayMap<String, ArrayList<Intent>>(); mStickyBroadcasts.put(userId, stickies); } ArrayList<Intent> list = stickies.get(intent.getAction()); if (list == null) { list = new ArrayList<Intent>(); stickies.put(intent.getAction(), list); } int N = list.size(); int i; for (i=0; i<N; i++) { if (intent.filterEquals(list.get(i))) { // This sticky already exists, replace it. list.set(i, new Intent(intent)); break; } } if (i >= N) { list.add(new Intent(intent)); } } int[] users; if (userId == UserHandle.USER_ALL) { // Caller wants broadcast to go to all started users. users = mStartedUserArray; } else { // Caller wants broadcast to go to one specific user. users = new int[] {userId}; } 6)先查詢靜態廣播保存到receivers中,再查詢動態廣播保存到registeredReceivers中 ===================================================== //找出誰都會收到這個廣播。 // Figure out who all will receive this broadcast. List receivers = null; List<BroadcastFilter> registeredReceivers = null; // Need to resolve the intent to interested receivers... //如果下面的if語句為true,表示找到所有靜態的廣播保存到receivers 中 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); } //如果if:true,則queryIntent查詢所有匹配intent的Receiver; 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中 registeredReceivers.addAll(registeredReceiversForUser); } } } else { registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId); } } 7)廣播的調度,和廣播的分發 ======= //是不是替換上1個相同的廣播,即:上次接受的1個廣播還未來得及轉發給接收者, //又馬上發送了1個相同的廣播。這這類情況下接受的getFlags()==1, //表示要替換舊的廣播,即replacePending = true; 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; //ordered表示是不是是1個無序的廣播,并且是registeredReceivers動態廣播 //這就說明動態廣播要優先于靜態廣播的注冊者 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) { //這個做了修改,把無序廣播的調度隊列封裝到BroadcastQueue.java這個類中 //去了,mParallelBroadcasts來表示 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. 8)合并靜態廣播receivers和靜態廣播registerReceivers列表為1個列表 ======= 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) { // Insert this broadcast record into the final list. receivers.add(it, curr); ir++; curr = null; it++; NT++; } else { // Skip to the next ResolveInfo in the final list. it++; curt = null; } } //合并動態廣播和靜態廣播,根據優先級來進行合并的算法@} } //如果沒有完全把registeredReceivers列表中的數據合并到receivers中, //就用while循環順次添加到recivers的末尾,由于它們是優先級最低的廣播接收者 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) { //廣播的分發,真正發送廣播的地方在BroadcastQueue.java中履行的 queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } return ActivityManager.BROADCAST_SUCCESS; }

Step4:接著來看看scheduleBroadcastsLocked()方法

public void scheduleBroadcastsLocked() { if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts [" + mQueueName + "]: current=" + mBroadcastsScheduled); if (mBroadcastsScheduled) { return; } //這個方法比較簡單,就發送了1個消息 BROADCAST_INTENT_MSG mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); mBroadcastsScheduled = true; }

Step5:履行消息BROADCAST_INTENT_MSG的地方:

private final class BroadcastHandler extends Handler { public BroadcastHandler(Looper looper) { super(looper, null, true); } @Override public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_INTENT_MSG: { if (DEBUG_BROADCAST) Slog.v( TAG, "Received BROADCAST_INTENT_MSG"); processNextBroadcast(true); } break; case BROADCAST_TIMEOUT_MSG: { synchronized (mService) { broadcastTimeoutLocked(true); } } break; } } };

以上方法履行processNextBroadcast(true);這個是最重要的調用廣播發送的方法了。

Step6:processNextBroadcast()方法的履行:

final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { BroadcastRecord r; if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast [" + mQueueName + "]: " + mParallelBroadcasts.size() + " broadcasts, " + mOrderedBroadcasts.size() + " ordered broadcasts"); mService.updateCpuStats(); if (fromMsg) { //這個表示前面的Scheduled還沒有履行,handleMessage中會接著處理 mBroadcastsScheduled = false; } // First, deliver any non-serialized broadcasts right away. //mParallelBroadcasts這個就是1個無序的廣播調度隊列 while (mParallelBroadcasts.size() > 0) { r = mParallelBroadcasts.remove(0); r.dispatchTime = SystemClock.uptimeMillis(); r.dispatchClockTime = System.currentTimeMillis(); final int N = r.receivers.size(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast [" + mQueueName + "] " + r); for (int i=0; i<N; i++) { Object target = r.receivers.get(i); if (DEBUG_BROADCAST) Slog.v(TAG, "Delivering non-ordered on [" + mQueueName + "] to registered " + target + ": " + r); //調用無序廣播 deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false); } addBroadcastToHistoryLocked(r); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast [" + mQueueName + "] " + r); } // Now take care of the next serialized one... // If we are waiting for a process to come up to handle the next // broadcast, then do nothing at this point. Just in case, we // check that the process we're waiting for still exists. //mPendingBroadcast 描寫的廣播的接收者有多是靜態注冊的。 if (mPendingBroadcast != null) { if (DEBUG_BROADCAST_LIGHT) { Slog.v(TAG, "processNextBroadcast [" + mQueueName + "]: waiting for " + mPendingBroadcast.curApp); } boolean isDead; synchronized (mService.mPidsSelfLocked) { ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid); isDead = proc == null || proc.crashing; } //如果它運行中,保持等待 if (!isDead) { // It's still alive, so keep waiting return; } else { Slog.w(TAG, "pending app [" + mQueueName + "]" + mPendingBroadcast.curApp + " died before responding to broadcast"); mPendingBroadcast.state = BroadcastRecord.IDLE; //如果它沒有運行,就準備給它發送1個廣播mPendingBroadcastRecvIndex mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; } } boolean looped = false; //有序廣播mOrderedBroadcasts的調度任務的處理 do { if (mOrderedBroadcasts.size() == 0) { // No more broadcasts pending, so all done! mService.scheduleAppGcsLocked(); if (looped) { // If we had finished the last ordered broadcast, then // make sure all processes have correct oom and sched // adjustments. mService.updateOomAdjLocked(); } return; } r = mOrderedBroadcasts.get(0); boolean forceReceive = false; // Ensure that even if something goes awry with the timeout // detection, we catch "hung" broadcasts here, discard them, // and continue to make progress. // // This is only done if the system is ready so that PRE_BOOT_COMPLETED // receivers don't get executed with timeouts. They're intended for // one time heavy lifting after system upgrades and can take // significant amounts of time. int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); //檢查廣播的的處理時間是不是在規定的時間完成 if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { Slog.w(TAG, "Hung broadcast [" + mQueueName + "] discarded after timeout failure:"+ " now=" + now + " dispatchTime=" + r.dispatchTime + " startTime=" + r.receiverTime + " intent=" + r.intent + " numReceivers=" + numReceivers + " nextReceiver=" + r.nextReceiver + " state=" + r.state); //置為idle狀態。 broadcastTimeoutLocked(false); // forcibly finish this broadcast forceReceive = true; r.state = BroadcastRecord.IDLE; } } if (r.state != BroadcastRecord.IDLE) { if (DEBUG_BROADCAST) Slog.d(TAG, "processNextBroadcast(" + mQueueName + ") called when not idle (state=" + r.state + ")"); return; } if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { // No more receivers for this broadcast! Send the final // result if requested... if (r.resultTo != null) { try { if (DEBUG_BROADCAST) { int seq = r.intent.getIntExtra("seq", -1); Slog.i(TAG, "Finishing broadcast [" + mQueueName + "] " + r.intent.getAction() + " seq=" + seq + " app=" + r.callerApp); + performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); // Set this to null so that the reference // (local and remote) isn't kept in the mBroadcastHistory. r.resultTo = null; } catch (RemoteException e) { r.resultTo = null; Slog.w(TAG, "Failure [" + mQueueName + "] sending broadcast result of " + r.intent, e); } } if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG"); //取消廣播刪除BROADCAST_TIMEOUT_MSG這個消息 cancelBroadcastTimeoutLocked(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast " + r); // ... and on to the next... addBroadcastToHistoryLocked(r); mOrderedBroadcasts.remove(0); r = null; looped = true; continue; } } while (r == null); // Get the next receiver... //獲得下1個廣播 int recIdx = r.nextReceiver++; // Keep track of when this receiver started, and make sure there // is a timeout message pending to kill it if need be. r.receiverTime = SystemClock.uptimeMillis(); if (recIdx == 0) { r.dispatchTime = r.receiverTime; r.dispatchClockTime = System.currentTimeMillis(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast [" + mQueueName + <
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 午夜视频日本 | 日本欧美一区二区三区片 | 国产精品成人免费福利 | 免费视频网站在线看视频 | 大香伊人久久 | 久久精品二区 | 精品国产免费一区二区三区五区 | 国产精品国产亚洲精品不卡 | 性欧美大战久久久久久久 | 中国性猛交xxxx乱大交 | 国产在线一区二区 | 亚洲婷婷影院 | 中文在线视频观看 | 国产精品亚洲欧美日韩区 | 亚洲春色第一页 | 男18视频在线观看 | 亚洲精品推荐 | 男女上下爽无遮挡午夜免费视频 | 日产免费线路一区二区三区 | 国产精品成人久久久久 | 成人国产一区 | 亚洲一区二区三区不卡视频 | 久久久欧美综合久久久久 | 国产1区2区在线观看 | 国产精品爱久久久久久久 | 伊人网五月天 | 亚洲伊人成综合人影院小说 | 久久不卡 | 黄色的视频网站在线观看 | 免费一级做a爰片久久毛片潮 | www精品视频| jizz 在线观看免费 | 亚洲欧美国产一区二区三区 | 亚洲综合国产一区二区三区 | 日本午夜视频在线 | 亚洲黄色网址 | 欧美一级特黄啪啪片免费看 | 日韩一级高清 | 男人边吃奶边做性视频 | 五月天免费在线视频 | 国产日产欧产精品精品推荐在线 |