Monkey启动的主流程
- 在main函数中调用了run方法
- 处理命令行选项(把外部传入的参数进行初始化处理)
- 加载包黑名单或白名单(如果指定)
- 如果没有从外部传-s参数,随机因子默认为0,就会在此处初始化,获取当前的时间戳为随机因子数
- 检查所有系统接口是否都可用(检查ActivityManager,IWindowManager,IPackageManager)
- 创建随机数生成器(注:传入的随机因子数一样的时候,每次的随机数出现的顺序也就是一样的,所以这里其实是一个伪随机数生成器)
- 根据不同的参数去初始化不同的事件源(MonkeySourceRandom类(随机生成事件)、MonkeySourceScript(从脚本获取事件)、MonkeySourceNetwork(从网络获取事件))
- 设置已设置的事件比例(替换系统默认的事件比例值)
- 验证事件源发生器(验证用户传递的事件数比例是否符合要求)
- 循环执行monkey事件(当没有出现系统报错或者当前执行事件数没有大于设置的事件数时一直会执行)
- 从步骤7初始化的mEventSource对象中取出事件
- 对事件进行注入执行
// Monkey的源码
public class Monkey {
//程序入口
public static void main(String[] args) {
Process.setArgV0("com.android.commands.monkey");
Logger.err.println("args: " + Arrays.toString(args));
// 1.调用run方法
int resultCode = (new Monkey()).run(args);
System.exit(resultCode);
}
private int run(String[] args) {
...
// 2.处理命令行选项
if (!processOptions()) {
return -1;
}
// 3.加载包黑名单或白名单(如果指定)。
if (!loadPackageLists()) {
return -1;
}
// 4.如果没有从外部传-s参数,随机因子默认为0,就会在此处初始化
if (mSeed == 0) {
mSeed = System.currentTimeMillis() + System.identityHashCode(this);
}
// 5.检查所有系统接口是否都可用(检查ActivityManager,IWindowManager,IPackageManager)
if (!getSystemInterfaces()) {
return -3;
}
// 6.创建随机数生成器
mRandom = new Random(mSeed);
// 7.根据不同的参数去初始化不同的事件源
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) {
...
mEventSource = new MonkeySourceRandomScript(mScriptFileNames,
mThrottle, mRandomizeThrottle, mRandom,
mProfileWaitTime, mDeviceSleepTime, mRandomizeScript);
} else if (mServerPort != -1) {try {
...
mEventSource = new MonkeySourceNetwork(mServerPort);
} else {
// 默认随机源
if (mVerbose >= 2) { // check seeding performance
Logger.out.println("// Seeded: " + mSeed);
}
mEventSource = new MonkeySourceRandom(mRandom, mMainApps,
mThrottle, mRandomizeThrottle, mPermissionTargetSystem);
mEventSource.setVerbose(mVerbose);
// 8.设置已设置的比例因子
for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) {
if (mFactors[i] <= 0.0f) {
((MonkeySourceRandom) mEventSource).setFactors(i, mFactors[i]);
}
}
// 在随机模式下,从activity开始
((MonkeySourceRandom) mEventSource).generateActivity();
}
// 9.验证源发生器
if (!mEventSource.validate()) {
return -5;
}
...
mNetworkMonitor.start();
// 10.循环执行monkey事件
int crashedAtCycle = runMonkeyCycles();
mNetworkMonitor.stop();
}
}
//循环monkey事件
private int runMonkeyCycles() {
...
// 循环执行monkey事件(当没有出现系统报错或者当前执行事件数没有大于设置的事件数时)
while (!systemCrashed && cycleCounter < mCount) {
11.从步骤7初始化的mEventSource对象中取出事件
MonkeyEvent ev = mEventSource.getNextEvent();
if (ev != null) {
12.对事件进行注入执行
int injectCode = ev.injectEvent(mWm, mAm, mVerbose);
...
}
...
}
}
验证事件源发生器(MonkeySourceRandom)
主要验证用户设置的各种事件数比例符不符合要求,然后再通过用户设置的事件数比例和系统的事件数比例进行调整。
- 验证源发生器
- 算出用户设置的事件比例总值和剩余比例值和剩余的事件数
- 如果用户请求是> 100%,直接返回false报出错误
- 如果用户指定了所有事件的权重,那么它们需要是100%,如果不是直接返回false报出错误
- 计算必要的调整(把剩余的比例进行均分)
- 通过调整默认值或将用户值翻转回>0来修复所有值(把均分的值重新计算分布到各个事件上)
- 最后,规范化并转换为运行求和(把所有的事件分布在0-100%的区间值中)
public class Monkey {
private int run(String[] args) {
// 1.验证源发生器
if (!mEventSource.validate()) {
return -5;
}
// 设置已设置的比例因子(有传参过来的就设置,没有传参的默认为0)
for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) {
if (mFactors[i] <= 0.0f) {
((MonkeySourceRandom) mEventSource).setFactors(i, mFactors[i]);
}
}
}
}
public class MonkeySourceRandom implements MonkeyEventSource {
public boolean validate() {
boolean ret = true;
...
//调用adjustEventFactors方法
return ret & adjustEventFactors();
}
//调整百分比(在应用用户值之后)
private boolean adjustEventFactors() {
// go through all values and compute totals for user & default values
// 检查所有值并计算用户和默认值的总数
float userSum = 0.0f;
float defaultSum = 0.0f;
int defaultCount = 0;
for (int i = 0; i < FACTORZ_COUNT; ++i) {
// 2.用户设置为零或负值
if (mFactors[i] <= 0.0f) {
// 这个地方为什么是减等于,因为初始化的时候设置的是负数值(Monkey类的processOptions()方法中初始化的时候可以看到)
userSum -= mFactors[i];
} else {
defaultSum += mFactors[i];
++defaultCount;
}
}
// 3.如果用户请求是> 100%,直接返回false报出错误
if (userSum > 100.0f) {
Logger.err.println("** Event weights > 100%");
return false;
}
// 4.如果用户指定了所有的权重,那么它们需要是100%
if (defaultCount == 0 && (userSum < 99.9f || userSum > 100.1f)) {
Logger.err.println("** Event weights != 100%");
return false;
}
// 5.计算必要的调整
float defaultsTarget = (100.0f - userSum);
float defaultsAdjustment = defaultsTarget / defaultSum;
// 6.通过调整默认值或将用户值翻转回>0来修复所有值
for (int i = 0; i < FACTORZ_COUNT; ++i) {
if (mFactors[i] <= 0.0f) { // user values are zero or negative
mFactors[i] = -mFactors[i];
} else {
mFactors[i] *= defaultsAdjustment;
}
}
if (mVerbose > 0) {
Logger.out.println("// Event percentages:");
for (int i = 0; i < FACTORZ_COUNT; ++i) {
Logger.out.println("// " + i + ": " + mFactors[i] + "%");
}
}
// 7.最后,规范化并转换为运行求和
float sum = 0.0f;
for (int i = 0; i < FACTORZ_COUNT; ++i) {
sum += mFactors[i] / 100.0f;
mFactors[i] = sum;
}
return true;
}
}
Monkey事件的生成
- 从mEventSource对象中取出事件,进行注入执行
- 如果队列为空,则首先生成事件
- 生成随机事件(根据随机数生成器生成的随机数 匹配在此区间内的事件)
- 把生成的事情添加到MonkeyEventQueue对象尾部
- 获取队列最前面的事件,移除出队列,返回给Monkey进行操作。
public class Monkey {
//循环monkey事件
private int runMonkeyCycles() {
...
// 循环执行monkey事件(当没有出现系统报错或者当前执行事件数没有大于设置的事件数时)
while (!systemCrashed && cycleCounter < mCount) {
1.从mEventSource对象中取出事件
MonkeyEvent ev = mEventSource.getNextEvent();
if (ev != null) {
对事件进行注入执行
int injectCode = ev.injectEvent(mWm, mAm, mVerbose);
...
}
...
}
public class MonkeySourceRandom implements MonkeyEventSource {
public MonkeyEvent getNextEvent() {
// 2.如果队列为空,则首先生成事件
if (mQ.isEmpty()) {
generateEvents();
}
mEventCount++;
// 5.获取最前面的值,移除出队列
MonkeyEvent e = mQ.getFirst();
mQ.removeFirst();
return e;
}
//3.生成随机事件
private void generateEvents() {
float cls = mRandom.nextFloat();
int lastKey = 0;
// 根据随机数生成器生成的随机数 匹配在此区间内的事件
if (cls < mFactors[FACTOR_TOUCH]) {
generatePointerEvent(mRandom, GESTURE_TAP);
return;
} else if (cls < mFactors[FACTOR_MOTION]) {
generatePointerEvent(mRandom, GESTURE_DRAG);
return;
} else if (cls < mFactors[FACTOR_PINCHZOOM]) {
generatePointerEvent(mRandom, GESTURE_PINCH_OR_ZOOM);
return;
} else if (cls < mFactors[FACTOR_TRACKBALL]) {
generateTrackballEvent(mRandom);
return;
} else if (cls < mFactors[FACTOR_ROTATION]) {
generateRotationEvent(mRandom);
return;
} else if (cls < mFactors[FACTOR_PERMISSION]) {
mQ.add(mPermissionUtil.generateRandomPermissionEvent(mRandom));
return;
}
...
//4.把生成的事情添加到MonkeyEventQueue对象中
mQ.addLast(e);
}
}
}