private final void processCurBroadcastLocked(BroadcastRecord r, ProcessRecord app)
      throws RemoteException {
    if (DEBUG_BROADCAST) Slog.v(TAG, "Process cur broadcast " + r + " for app " + app);
    if (app.thread == null) {
      throw new RemoteException();
    }
    r.receiver = app.thread.asBinder();
    r.curApp = app;
    app.curReceiver = r;
    mService.updateLruProcessLocked(app, true);

    // Tell the application to launch this receiver.
    r.intent.setComponent(r.curComponent);

    boolean started = false;
    try {
      if (DEBUG_BROADCAST_LIGHT)
        Slog.v(TAG, "Delivering to component " + r.curComponent + ": " + r);
      mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
      app.thread.scheduleReceiver(
          new Intent(r.intent),
          r.curReceiver,
          mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
          r.resultCode,
          r.resultData,
          r.resultExtras,
          r.ordered,
          r.userId);
      if (DEBUG_BROADCAST) Slog.v(TAG, "Process cur broadcast " + r + " DELIVERED for app " + app);
      started = true;
    } finally {
      if (!started) {
        if (DEBUG_BROADCAST) Slog.v(TAG, "Process cur broadcast " + r + ": NOT STARTED!");
        r.receiver = null;
        r.curApp = null;
        app.curReceiver = null;
      }
    }
  }
  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) {
        mBroadcastsScheduled = false;
      }

      // First, deliver any non-serialized broadcasts right away.
      while (mParallelBroadcasts.size() > 0) {
        r = mParallelBroadcasts.remove(0);
        r.dispatchTime = SystemClock.uptimeMillis();
        r.dispatchClockTime = System.currentTimeMillis();
        mCurrentBroadcast = r;
        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);
        mCurrentBroadcast = null;
        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.
      if (mPendingBroadcast != null) {
        if (DEBUG_BROADCAST_LIGHT) {
          Slog.v(
              TAG,
              "processNextBroadcast [" + mQueueName + "]: waiting for " + mPendingBroadcast.curApp);
        }

        boolean isDead;
        synchronized (mService.mPidsSelfLocked) {
          isDead = (mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
        }
        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;
          mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
          mPendingBroadcast = null;
        }
      }

      boolean looped = false;

      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);
        mCurrentBroadcast = r;
        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);
            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) isnt kept in the mBroadcastHistory.
              r.resultTo = null;
            } catch (RemoteException e) {
              Slog.w(
                  TAG, "Failure [" + mQueueName + "] sending broadcast result of " + r.intent, e);
            }
          }

          if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling 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);
          mCurrentBroadcast = null;
          r = null;
          looped = true;
          continue;
        }
      } while (r == null);

      // Get the next receiver...
      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 + "] " + r);
      }
      if (!mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mTimeoutPeriod;
        if (DEBUG_BROADCAST)
          Slog.v(
              TAG,
              "Submitting BROADCAST_TIMEOUT_MSG ["
                  + mQueueName
                  + "] for "
                  + r
                  + " at "
                  + timeoutTime);
        setBroadcastTimeoutLocked(timeoutTime);
      }

      Object nextReceiver = r.receivers.get(recIdx);
      if (nextReceiver instanceof BroadcastFilter) {
        // Simple case: this is a registered receiver who gets
        // a direct call.
        BroadcastFilter filter = (BroadcastFilter) nextReceiver;
        if (DEBUG_BROADCAST)
          Slog.v(TAG, "Delivering ordered [" + mQueueName + "] to registered " + filter + ": " + r);
        deliverToRegisteredReceiverLocked(r, filter, r.ordered);
        if (r.receiver == null || !r.ordered) {
          // The receiver has already finished, so schedule to
          // process the next one.
          if (DEBUG_BROADCAST)
            Slog.v(
                TAG,
                "Quick finishing ["
                    + mQueueName
                    + "]: ordered="
                    + r.ordered
                    + " receiver="
                    + r.receiver);
          r.state = BroadcastRecord.IDLE;
          scheduleBroadcastsLocked();
        }
        return;
      }

      // Hard case: need to instantiate the receiver, possibly
      // starting its application process to host it.

      ResolveInfo info = (ResolveInfo) nextReceiver;
      ComponentName component =
          new ComponentName(info.activityInfo.applicationInfo.packageName, info.activityInfo.name);

      boolean skip = false;
      int perm =
          mService.checkComponentPermission(
              info.activityInfo.permission,
              r.callingPid,
              r.callingUid,
              info.activityInfo.applicationInfo.uid,
              info.activityInfo.exported);
      if (perm != PackageManager.PERMISSION_GRANTED) {
        if (!info.activityInfo.exported) {
          Slog.w(
              TAG,
              "Permission Denial: broadcasting "
                  + r.intent.toString()
                  + " from "
                  + r.callerPackage
                  + " (pid="
                  + r.callingPid
                  + ", uid="
                  + r.callingUid
                  + ")"
                  + " is not exported from uid "
                  + info.activityInfo.applicationInfo.uid
                  + " due to receiver "
                  + component.flattenToShortString());
        } else {
          Slog.w(
              TAG,
              "Permission Denial: broadcasting "
                  + r.intent.toString()
                  + " from "
                  + r.callerPackage
                  + " (pid="
                  + r.callingPid
                  + ", uid="
                  + r.callingUid
                  + ")"
                  + " requires "
                  + info.activityInfo.permission
                  + " due to receiver "
                  + component.flattenToShortString());
        }
        skip = true;
      }
      if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID
          && r.requiredPermission != null) {
        try {
          perm =
              AppGlobals.getPackageManager()
                  .checkPermission(
                      r.requiredPermission, info.activityInfo.applicationInfo.packageName);
        } catch (RemoteException e) {
          perm = PackageManager.PERMISSION_DENIED;
        }
        if (perm != PackageManager.PERMISSION_GRANTED) {
          Slog.w(
              TAG,
              "Permission Denial: receiving "
                  + r.intent
                  + " to "
                  + component.flattenToShortString()
                  + " requires "
                  + r.requiredPermission
                  + " due to sender "
                  + r.callerPackage
                  + " (uid "
                  + r.callingUid
                  + ")");
          skip = true;
        }
      }
      if (r.appOp != AppOpsManager.OP_NONE) {
        int mode =
            mService.mAppOpsService.checkOperation(
                r.appOp, info.activityInfo.applicationInfo.uid, info.activityInfo.packageName);
        if (mode != AppOpsManager.MODE_ALLOWED) {
          if (DEBUG_BROADCAST)
            Slog.v(
                TAG,
                "App op "
                    + r.appOp
                    + " not allowed for broadcast to uid "
                    + info.activityInfo.applicationInfo.uid
                    + " pkg "
                    + info.activityInfo.packageName);
          skip = true;
        }
      }
      // MUTT
      if (mMuttFilter.hasAction(r.intent.getAction())) {
        Slog.v(TAG, "MUTT: whitelist broadcast " + r.intent.toString());
      } else {
        if (mService.mBatteryStatsService.allowMutt(
                info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
            != 0) {
          Slog.w(
              TAG,
              "MUTT: skipping broadcasting "
                  + r.intent.toString()
                  + " from "
                  + r.callerPackage
                  + " (pid="
                  + r.callingPid
                  + ", uid="
                  + r.callingUid
                  + " to "
                  + component.flattenToShortString()
                  + ")");

          skip = true;
        }
      }

      boolean isSingleton = false;
      try {
        isSingleton =
            mService.isSingleton(
                info.activityInfo.processName,
                info.activityInfo.applicationInfo,
                info.activityInfo.name,
                info.activityInfo.flags);
      } catch (SecurityException e) {
        Slog.w(TAG, e.getMessage());
        skip = true;
      }
      if ((info.activityInfo.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
        if (ActivityManager.checkUidPermission(
                android.Manifest.permission.INTERACT_ACROSS_USERS,
                info.activityInfo.applicationInfo.uid)
            != PackageManager.PERMISSION_GRANTED) {
          Slog.w(
              TAG,
              "Permission Denial: Receiver "
                  + component.flattenToShortString()
                  + " requests FLAG_SINGLE_USER, but app does not hold "
                  + android.Manifest.permission.INTERACT_ACROSS_USERS);
          skip = true;
        }
      }
      if (r.curApp != null && r.curApp.crashing) {
        // If the target process is crashing, just skip it.
        if (DEBUG_BROADCAST)
          Slog.v(
              TAG,
              "Skipping deliver ordered ["
                  + mQueueName
                  + "] "
                  + r
                  + " to "
                  + r.curApp
                  + ": process crashing");
        skip = true;
      }

      if (skip) {
        if (DEBUG_BROADCAST)
          Slog.v(
              TAG,
              "Skipping delivery of ordered [" + mQueueName + "] " + r + " for whatever reason");
        r.receiver = null;
        r.curFilter = null;
        r.state = BroadcastRecord.IDLE;
        scheduleBroadcastsLocked();
        return;
      }

      r.state = BroadcastRecord.APP_RECEIVE;
      String targetProcess = info.activityInfo.processName;
      r.curComponent = component;
      if (r.callingUid != Process.SYSTEM_UID && isSingleton) {
        info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
      }
      r.curReceiver = info.activityInfo;
      if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
        Slog.v(
            TAG_MU,
            "Updated broadcast record activity info for secondary user, "
                + info.activityInfo
                + ", callingUid = "
                + r.callingUid
                + ", uid = "
                + info.activityInfo.applicationInfo.uid);
      }

      // Broadcast is being executed, its package can't be stopped.
      try {
        AppGlobals.getPackageManager()
            .setPackageStoppedState(
                r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
      } catch (RemoteException e) {
      } catch (IllegalArgumentException e) {
        Slog.w(
            TAG, "Failed trying to unstop package " + r.curComponent.getPackageName() + ": " + e);
      }

      // Is this receiver's application already running?
      ProcessRecord app =
          mService.getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid);
      if (app != null && app.thread != null) {
        try {
          app.addPackage(info.activityInfo.packageName);
          processCurBroadcastLocked(r, app);
          return;
        } catch (RemoteException e) {
          Slog.w(TAG, "Exception when sending broadcast to " + r.curComponent, e);
        } catch (RuntimeException e) {
          Log.wtf(TAG, "Failed sending broadcast to " + r.curComponent + " with " + r.intent, e);
          // If some unexpected exception happened, just skip
          // this broadcast.  At this point we are not in the call
          // from a client, so throwing an exception out from here
          // will crash the entire system instead of just whoever
          // sent the broadcast.
          logBroadcastReceiverDiscardLocked(r);
          finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, true);
          scheduleBroadcastsLocked();
          // We need to reset the state if we failed to start the receiver.
          r.state = BroadcastRecord.IDLE;
          return;
        }

        // If a dead object exception was thrown -- fall through to
        // restart the application.
      }

      // Not running -- get it started, to be executed when the app comes up.
      if (DEBUG_BROADCAST)
        Slog.v(
            TAG, "Need to start app [" + mQueueName + "] " + targetProcess + " for broadcast " + r);
      if ((r.curApp =
              mService.startProcessLocked(
                  targetProcess,
                  info.activityInfo.applicationInfo,
                  true,
                  r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
                  "broadcast",
                  r.curComponent,
                  (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0,
                  false))
          == null) {
        // Ah, this recipient is unavailable.  Finish it if necessary,
        // and mark the broadcast record as ready for the next.
        Slog.w(
            TAG,
            "Unable to launch app "
                + info.activityInfo.applicationInfo.packageName
                + "/"
                + info.activityInfo.applicationInfo.uid
                + " for broadcast "
                + r.intent
                + ": process is bad");
        logBroadcastReceiverDiscardLocked(r);
        finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, true);
        scheduleBroadcastsLocked();
        r.state = BroadcastRecord.IDLE;
        return;
      }

      mPendingBroadcast = r;
      mPendingBroadcastRecvIndex = recIdx;
    }
  }
  private final void deliverToRegisteredReceiverLocked(
      BroadcastRecord r, BroadcastFilter filter, boolean ordered) {
    boolean skip = false;
    if (filter.requiredPermission != null) {
      int perm =
          mService.checkComponentPermission(
              filter.requiredPermission, r.callingPid, r.callingUid, -1, true);
      if (perm != PackageManager.PERMISSION_GRANTED) {
        Slog.w(
            TAG,
            "Permission Denial: broadcasting "
                + r.intent.toString()
                + " from "
                + r.callerPackage
                + " (pid="
                + r.callingPid
                + ", uid="
                + r.callingUid
                + ")"
                + " requires "
                + filter.requiredPermission
                + " due to registered receiver "
                + filter);
        skip = true;
      }
    }
    if (!skip && r.requiredPermission != null) {
      int perm =
          mService.checkComponentPermission(
              r.requiredPermission, filter.receiverList.pid, filter.receiverList.uid, -1, true);
      if (perm != PackageManager.PERMISSION_GRANTED) {
        Slog.w(
            TAG,
            "Permission Denial: receiving "
                + r.intent.toString()
                + " to "
                + filter.receiverList.app
                + " (pid="
                + filter.receiverList.pid
                + ", uid="
                + filter.receiverList.uid
                + ")"
                + " requires "
                + r.requiredPermission
                + " due to sender "
                + r.callerPackage
                + " (uid "
                + r.callingUid
                + ")");
        skip = true;
      }
    }

    if (r.appOp != AppOpsManager.OP_NONE) {
      int mode =
          mService.mAppOpsService.checkOperation(
              r.appOp, filter.receiverList.uid, filter.packageName);
      if (mode != AppOpsManager.MODE_ALLOWED) {
        if (DEBUG_BROADCAST)
          Slog.v(
              TAG,
              "App op "
                  + r.appOp
                  + " not allowed for broadcast to uid "
                  + filter.receiverList.uid
                  + " pkg "
                  + filter.packageName);
        skip = true;
      }
    }

    if (!skip) {
      // If this is not being sent as an ordered broadcast, then we
      // don't want to touch the fields that keep track of the current
      // state of ordered broadcasts.
      if (ordered) {
        r.receiver = filter.receiverList.receiver.asBinder();
        r.curFilter = filter;
        filter.receiverList.curBroadcast = r;
        r.state = BroadcastRecord.CALL_IN_RECEIVE;
        if (filter.receiverList.app != null) {
          // Bump hosting application to no longer be in background
          // scheduling class.  Note that we can't do that if there
          // isn't an app...  but we can only be in that case for
          // things that directly call the IActivityManager API, which
          // are already core system stuff so don't matter for this.
          r.curApp = filter.receiverList.app;
          filter.receiverList.app.curReceiver = r;
          mService.updateOomAdjLocked();
        }
      }
      try {
        if (DEBUG_BROADCAST_LIGHT) {
          int seq = r.intent.getIntExtra("seq", -1);
          Slog.i(TAG, "Delivering to " + filter + " (seq=" + seq + "): " + r);
        }
        performReceiveLocked(
            filter.receiverList.app,
            filter.receiverList.receiver,
            new Intent(r.intent),
            r.resultCode,
            r.resultData,
            r.resultExtras,
            r.ordered,
            r.initialSticky,
            r.userId);
        if (ordered) {
          r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
      } catch (RemoteException e) {
        Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
        if (ordered) {
          r.receiver = null;
          r.curFilter = null;
          filter.receiverList.curBroadcast = null;
          if (filter.receiverList.app != null) {
            filter.receiverList.app.curReceiver = null;
          }
        }
      }
    }
  }
  final void broadcastTimeoutLocked(boolean fromMsg) {
    if (fromMsg) {
      mPendingBroadcastTimeoutMessage = false;
    }

    if (mOrderedBroadcasts.size() == 0) {
      return;
    }

    long now = SystemClock.uptimeMillis();
    BroadcastRecord r = mOrderedBroadcasts.get(0);
    if (fromMsg) {
      if (mService.mDidDexOpt) {
        // Delay timeouts until dexopt finishes.
        mService.mDidDexOpt = false;
        long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
        setBroadcastTimeoutLocked(timeoutTime);
        return;
      }
      if (!mService.mProcessesReady) {
        // Only process broadcast timeouts if the system is ready. That way
        // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
        // to do heavy lifting for system up.
        return;
      }

      long timeoutTime = r.receiverTime + mTimeoutPeriod;
      if (timeoutTime > now) {
        // We can observe premature timeouts because we do not cancel and reset the
        // broadcast timeout message after each receiver finishes.  Instead, we set up
        // an initial timeout then kick it down the road a little further as needed
        // when it expires.
        if (DEBUG_BROADCAST)
          Slog.v(
              TAG,
              "Premature timeout ["
                  + mQueueName
                  + "] @ "
                  + now
                  + ": resetting BROADCAST_TIMEOUT_MSG for "
                  + timeoutTime);
        setBroadcastTimeoutLocked(timeoutTime);
        return;
      }
    }

    Slog.w(
        TAG,
        "Timeout of broadcast "
            + r
            + " - receiver="
            + r.receiver
            + ", started "
            + (now - r.receiverTime)
            + "ms ago");
    r.receiverTime = now;
    r.anrCount++;

    // Current receiver has passed its expiration date.
    if (r.nextReceiver <= 0) {
      Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
      return;
    }

    ProcessRecord app = null;
    String anrMessage = null;

    Object curReceiver = r.receivers.get(r.nextReceiver - 1);
    Slog.w(TAG, "Receiver during timeout: " + curReceiver);
    logBroadcastReceiverDiscardLocked(r);
    if (curReceiver instanceof BroadcastFilter) {
      BroadcastFilter bf = (BroadcastFilter) curReceiver;
      if (bf.receiverList.pid != 0 && bf.receiverList.pid != ActivityManagerService.MY_PID) {
        synchronized (mService.mPidsSelfLocked) {
          app = mService.mPidsSelfLocked.get(bf.receiverList.pid);
        }
      }
    } else {
      app = r.curApp;
    }

    if (app != null) {
      anrMessage = "Broadcast of " + r.intent.toString();
    }

    if (mPendingBroadcast == r) {
      mPendingBroadcast = null;
    }

    // Move on to the next receiver.
    finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, true);
    scheduleBroadcastsLocked();

    if (anrMessage != null) {
      // Post the ANR to the handler since we do not want to process ANRs while
      // potentially holding our lock.
      mHandler.post(new AppNotResponding(app, anrMessage));
    }
  }