/**
   * Run mCount cycles and see if we hit any crashers.
   *
   * <p>TODO: Meta state on keys
   *
   * @return Returns the last cycle which executed. If the value == mCount, no errors detected.
   */
  private int runMonkeyCycles() {
    int eventCounter = 0;
    int cycleCounter = 0;

    boolean systemCrashed = false;

    // TO DO : The count should apply to each of the script file.
    while (!systemCrashed && cycleCounter < mCount) {
      synchronized (this) {
        if (mRequestProcRank) {
          reportProcRank();
          mRequestProcRank = false;
        }
        if (mRequestAnrTraces) {
          reportAnrTraces();
          mRequestAnrTraces = false;
        }
        if (mRequestAnrBugreport) {
          getBugreport("anr_" + mReportProcessName + "_");
          mRequestAnrBugreport = false;
        }
        if (mRequestAppCrashBugreport) {
          getBugreport("app_crash" + mReportProcessName + "_");
          mRequestAppCrashBugreport = false;
        }
        if (mRequestDumpsysMemInfo) {
          reportDumpsysMemInfo();
          mRequestDumpsysMemInfo = false;
        }
        if (mMonitorNativeCrashes) {
          // first time through, when eventCounter == 0, just set up
          // the watcher (ignore the error)
          if (checkNativeCrashes() && (eventCounter > 0)) {
            System.out.println("** New native crash detected.");
            if (mRequestBugreport) {
              getBugreport("native_crash_");
            }
            mAbort = mAbort || !mIgnoreNativeCrashes || mKillProcessAfterError;
          }
        }
        if (mAbort) {
          System.out.println("** Monkey aborted due to error.");
          System.out.println("Events injected: " + eventCounter);
          return eventCounter;
        }
      }

      // In this debugging mode, we never send any events. This is
      // primarily here so you can manually test the package or category
      // limits, while manually exercising the system.
      if (mSendNoEvents) {
        eventCounter++;
        cycleCounter++;
        continue;
      }

      if ((mVerbose > 0) && (eventCounter % 100) == 0 && eventCounter != 0) {
        String calendarTime = MonkeyUtils.toCalendarTime(System.currentTimeMillis());
        long systemUpTime = SystemClock.elapsedRealtime();
        System.out.println(
            "    //[calendar_time:" + calendarTime + " system_uptime:" + systemUpTime + "]");
        System.out.println("    // Sending event #" + eventCounter);
      }

      MonkeyEvent ev = mEventSource.getNextEvent();
      if (ev != null) {
        int injectCode = ev.injectEvent(mWm, mAm, mVerbose);
        if (injectCode == MonkeyEvent.INJECT_FAIL) {
          if (ev instanceof MonkeyKeyEvent) {
            mDroppedKeyEvents++;
          } else if (ev instanceof MonkeyMotionEvent) {
            mDroppedPointerEvents++;
          } else if (ev instanceof MonkeyFlipEvent) {
            mDroppedFlipEvents++;
          }
        } else if (injectCode == MonkeyEvent.INJECT_ERROR_REMOTE_EXCEPTION) {
          systemCrashed = true;
          System.err.println("** Error: RemoteException while injecting event.");
        } else if (injectCode == MonkeyEvent.INJECT_ERROR_SECURITY_EXCEPTION) {
          systemCrashed = !mIgnoreSecurityExceptions;
          if (systemCrashed) {
            System.err.println("** Error: SecurityException while injecting event.");
          }
        }

        // Don't count throttling as an event.
        if (!(ev instanceof MonkeyThrottleEvent)) {
          eventCounter++;
          if (mCountEvents) {
            cycleCounter++;
            if (mScriptLog) {
              writeScriptLog(cycleCounter);
            }
          }
        }
      } else {
        if (!mCountEvents) {
          cycleCounter++;
          if (mScriptLog) {
            writeScriptLog(cycleCounter);
          }
        } else {
          // Event Source has signaled that we have no more events to process
          break;
        }
      }
    }
    System.out.println("Events injected: " + eventCounter);
    return eventCounter;
  }