/** * Run the command! * * @param args The command-line arguments * @return Returns a posix-style result code. 0 for no error. */ private int run(String[] args) { // Super-early debugger wait for (String s : args) { if ("--wait-dbg".equals(s)) { Debug.waitForDebugger(); } } // Default values for some command-line options mVerbose = 0; mCount = 1000; mSeed = 0; mThrottle = 0; // prepare for command-line processing mArgs = args; mNextArg = 0; // set a positive value, indicating none of the factors is provided yet for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) { mFactors[i] = 1.0f; } if (!processOptions()) { return -1; } if (!loadPackageLists()) { return -1; } // now set up additional data in preparation for launch if (mMainCategories.size() == 0) { mMainCategories.add(Intent.CATEGORY_LAUNCHER); mMainCategories.add(Intent.CATEGORY_MONKEY); } if (mVerbose > 0) { System.out.println(":Monkey: seed=" + mSeed + " count=" + mCount); if (mValidPackages.size() > 0) { Iterator<String> it = mValidPackages.iterator(); while (it.hasNext()) { System.out.println(":AllowPackage: " + it.next()); } } if (mInvalidPackages.size() > 0) { Iterator<String> it = mInvalidPackages.iterator(); while (it.hasNext()) { System.out.println(":DisallowPackage: " + it.next()); } } if (mMainCategories.size() != 0) { Iterator<String> it = mMainCategories.iterator(); while (it.hasNext()) { System.out.println(":IncludeCategory: " + it.next()); } } } if (!checkInternalConfiguration()) { return -2; } if (!getSystemInterfaces()) { return -3; } if (!getMainApps()) { return -4; } mRandom = new SecureRandom(); mRandom.setSeed((mSeed == 0) ? -1 : mSeed); if (mScriptFileNames != null && mScriptFileNames.size() == 1) { // script mode, ignore other options mEventSource = new MonkeySourceScript( mRandom, mScriptFileNames.get(0), mThrottle, mRandomizeThrottle, mProfileWaitTime, mDeviceSleepTime); mEventSource.setVerbose(mVerbose); mCountEvents = false; } else if (mScriptFileNames != null && mScriptFileNames.size() > 1) { if (mSetupFileName != null) { mEventSource = new MonkeySourceRandomScript( mSetupFileName, mScriptFileNames, mThrottle, mRandomizeThrottle, mRandom, mProfileWaitTime, mDeviceSleepTime, mRandomizeScript); mCount++; } else { mEventSource = new MonkeySourceRandomScript( mScriptFileNames, mThrottle, mRandomizeThrottle, mRandom, mProfileWaitTime, mDeviceSleepTime, mRandomizeScript); } mEventSource.setVerbose(mVerbose); mCountEvents = false; } else if (mServerPort != -1) { try { mEventSource = new MonkeySourceNetwork(mServerPort); } catch (IOException e) { System.out.println("Error binding to network socket."); return -5; } mCount = Integer.MAX_VALUE; } else { // random source by default if (mVerbose >= 2) { // check seeding performance System.out.println("// Seeded: " + mSeed); } mEventSource = new MonkeySourceRandom(mRandom, mMainApps, mThrottle, mRandomizeThrottle); mEventSource.setVerbose(mVerbose); // set any of the factors that has been set for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) { if (mFactors[i] <= 0.0f) { ((MonkeySourceRandom) mEventSource).setFactors(i, mFactors[i]); } } // in random mode, we start with a random activity ((MonkeySourceRandom) mEventSource).generateActivity(); } // validate source generator if (!mEventSource.validate()) { return -5; } // If we're profiling, do it immediately before/after the main monkey // loop if (mGenerateHprof) { signalPersistentProcesses(); } mNetworkMonitor.start(); int crashedAtCycle = runMonkeyCycles(); mNetworkMonitor.stop(); synchronized (this) { if (mRequestAnrTraces) { reportAnrTraces(); mRequestAnrTraces = false; } if (mRequestAnrBugreport) { System.out.println("Print the anr report"); getBugreport("anr_" + mReportProcessName + "_"); mRequestAnrBugreport = false; } if (mRequestAppCrashBugreport) { getBugreport("app_crash" + mReportProcessName + "_"); mRequestAppCrashBugreport = false; } if (mRequestDumpsysMemInfo) { reportDumpsysMemInfo(); mRequestDumpsysMemInfo = false; } } if (mGenerateHprof) { signalPersistentProcesses(); if (mVerbose > 0) { System.out.println("// Generated profiling reports in /data/misc"); } } try { mAm.setActivityController(null); mNetworkMonitor.unregister(mAm); } catch (RemoteException e) { // just in case this was latent (after mCount cycles), make sure // we report it if (crashedAtCycle >= mCount) { crashedAtCycle = mCount - 1; } } // report dropped event stats if (mVerbose > 0) { System.out.print(":Dropped: keys="); System.out.print(mDroppedKeyEvents); System.out.print(" pointers="); System.out.print(mDroppedPointerEvents); System.out.print(" trackballs="); System.out.print(mDroppedTrackballEvents); System.out.print(" flips="); System.out.println(mDroppedFlipEvents); } // report network stats mNetworkMonitor.dump(); if (crashedAtCycle < mCount - 1) { System.err.println( "** System appears to have crashed at event " + crashedAtCycle + " of " + mCount + " using seed " + mSeed); return crashedAtCycle; } else { if (mVerbose > 0) { System.out.println("// Monkey finished"); } return 0; } }
/** * 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; }