今天,承接上文 【Android Monkey源码解析二】- 参数解析 中提到的Monkey主类进行继续解析。
java
/**
* 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) {
...
// now set up additional data in preparation for launch
// 如果在命令行参数中没有指定category(-c)的情况下,添加CATEGORY_LAUNCHER和CATEGORY_MONKEY
if (mMainCategories.size() == 0) {
mMainCategories.add(Intent.CATEGORY_LAUNCHER);
mMainCategories.add(Intent.CATEGORY_MONKEY);
}
// 如果没有设置随机种子值,则自动生成
if (mSeed == 0) {
mSeed = System.currentTimeMillis() + System.identityHashCode(this);
}
if (mVerbose > 0) {
// 打印所有的包信息和Category信息
Logger.out.println(":Monkey: seed=" + mSeed + " count=" + mCount);
MonkeyUtils.getPackageFilter().dump();
if (mMainCategories.size() != 0) {
Iterator<String> it = mMainCategories.iterator();
while (it.hasNext()) {
Logger.out.println(":IncludeCategory: " + it.next());
}
}
}
// 这个目前没有使用到,在此类中,没有任何的逻辑,都是直接返回true
if (!checkInternalConfiguration()) {
return -2;
}
// 如果获取ActivityManager,WindowManager,PackageManager系统接口对象出现异常,就直接退出
if (!getSystemInterfaces()) {
return -3;
}
// 此方法的处理,主要是通过Intent结合ACTION_MAIN和通过命令行设置的categories或默认的categories,
// 获取手机系统上所有满足条件的应用集合;然后,再跟设置的MonkeyUtils中设置的validPackages进行对比
// 过滤,若过滤后仍没有交集,则程序直接退出;若有满足的条件,则添加到mMainApps集合对象中。
if (!getMainApps()) {
return -4;
}
// 初始化Random对象,以供后续的随机事件调用
mRandom = new Random(mSeed);
// 如果命令行指令有设置Monkey的脚本参数,则进入此逻辑处理
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) {
// 如果命令行指令有设置多个Monkey的脚本参数,则进入此逻辑处理
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) {
Logger.out.println("Error binding to network socket.");
return -5;
}
mCount = Integer.MAX_VALUE;
} else {
// random source by default 如果不是上面三种情况,则进入默认的随机事件模式
if (mVerbose >= 2) { // check seeding performance
Logger.out.println("// Seeded: " + mSeed);
}
mEventSource = new MonkeySourceRandom(mRandom, mMainApps,
mThrottle, mRandomizeThrottle, mPermissionTargetSystem);
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
// 首先,生成一个随机的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 = 0;
try {
// 执行Monkey循环事件
crashedAtCycle = runMonkeyCycles();
} finally {
// Release the rotation lock if it's still held and restore the
// original orientation.
new MonkeyRotationEvent(Surface.ROTATION_0, false).injectEvent(
mWm, mAm, mVerbose);
}
mNetworkMonitor.stop();
synchronized (this) {
if (mRequestAnrTraces) {
reportAnrTraces();
mRequestAnrTraces = false;
}
if (mRequestAnrBugreport){
Logger.out.println("Print the anr report");
getBugreport("anr_" + mReportProcessName + "_");
mRequestAnrBugreport = false;
}
if (mRequestWatchdogBugreport) {
Logger.out.println("Print the watchdog report");
getBugreport("anr_watchdog_");
mRequestWatchdogBugreport = false;
}
if (mRequestAppCrashBugreport){
getBugreport("app_crash" + mReportProcessName + "_");
mRequestAppCrashBugreport = false;
}
if (mRequestDumpsysMemInfo) {
reportDumpsysMemInfo();
mRequestDumpsysMemInfo = false;
}
if (mRequestPeriodicBugreport){
getBugreport("Bugreport_");
mRequestPeriodicBugreport = false;
}
if (mWatchdogWaiting) {
mWatchdogWaiting = false;
notifyAll();
}
}
if (mGenerateHprof) {
signalPersistentProcesses();
if (mVerbose > 0) {
Logger.out.println("// Generated profiling reports in /data/misc");
}
}
// 取消ActivityController的设置
try {
mAm.setActivityController(null, true);
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) {
Logger.out.println(":Dropped: keys=" + mDroppedKeyEvents
+ " pointers=" + mDroppedPointerEvents
+ " trackballs=" + mDroppedTrackballEvents
+ " flips=" + mDroppedFlipEvents
+ " rotations=" + mDroppedRotationEvents);
}
// report network stats
mNetworkMonitor.dump();
if (crashedAtCycle < mCount - 1) {
Logger.err.println("** System appears to have crashed at event " + crashedAtCycle
+ " of " + mCount + " using seed " + mSeed);
return crashedAtCycle;
} else {
if (mVerbose > 0) {
Logger.out.println("// Monkey finished");
}
return 0;
}
}
getSystemInterfaces方法通过远程调用的方式,分别获取系统的接口对象ActivityManager(mAm,后续用于判断和控制Activity的进入,主要通过设置ActivityController来实现),WindowManager(mWm ,用于处理输入等),PackageManager(mPm,获取包相关的信息 ):
java
/**
* Attach to the required system interfaces.
*
* @return Returns true if all system interfaces were available.
*/
private boolean getSystemInterfaces() {
mAm = ActivityManager.getService();
if (mAm == null) {
Logger.err.println("** Error: Unable to connect to activity manager; is the system "
+ "running?");
return false;
}
mWm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
if (mWm == null) {
Logger.err.println("** Error: Unable to connect to window manager; is the system "
+ "running?");
return false;
}
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
if (mPm == null) {
Logger.err.println("** Error: Unable to connect to package manager; is the system "
+ "running?");
return false;
}
try {
mAm.setActivityController(new ActivityController(), true);
mNetworkMonitor.register(mAm);
} catch (RemoteException e) {
Logger.err.println("** Failed talking with activity manager!");
return false;
}
return true;
}
后续,我们将首先分析Monkey的异常捕获和页面控制。