3. 随机运行模式
在上个小节中,monkey有4种运行模式,原理都是一样的,就以随机运行模式为例来论述。
3.1 准备工作
在run方法中,有关随机运行模式代码如下,
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
((MonkeySourceRandom) mEventSource).generateActivity();
首先构造MonkeySourceRandom对象,然后调用其setFactors设置事件的百分比,最后调用generateActivity方法。
MonkeySourceRandom的构造方法如下,
public MonkeySourceRandom(Random random, List<ComponentName> MainApps,
long throttle, boolean randomizeThrottle, boolean permissionTargetSystem) {
// default values for random distributions
// note, these are straight percentages, to match user input (cmd line args)
// but they will be converted to 0..1 values before the main loop runs.
mFactors[FACTOR_TOUCH] = 15.0f; // 为这些事件所占百分比赋初值。
mFactors[FACTOR_MOTION] = 10.0f;
mFactors[FACTOR_TRACKBALL] = 15.0f;
// Adjust the values if we want to enable rotation by default.
mFactors[FACTOR_ROTATION] = 0.0f;
mFactors[FACTOR_NAV] = 25.0f;
mFactors[FACTOR_MAJORNAV] = 15.0f;
mFactors[FACTOR_SYSOPS] = 2.0f;
mFactors[FACTOR_APPSWITCH] = 2.0f;
mFactors[FACTOR_FLIP] = 1.0f;
// disbale permission by default
mFactors[FACTOR_PERMISSION] = 0.0f;
mFactors[FACTOR_ANYTHING] = 13.0f;
mFactors[FACTOR_PINCHZOOM] = 2.0f;
mRandom = random;
mMainApps = MainApps;
// 构造一个MonkeyEventQueue 对象
mQ = new MonkeyEventQueue(random, throttle, randomizeThrottle);
mPermissionUtil = new MonkeyPermissionUtil();
mPermissionUtil.setTargetSystemPackages(permissionTargetSystem);
}
MonkeyEventQueue定义如下,
public class MonkeyEventQueue extends LinkedList<MonkeyEvent> {
private Random mRandom;
private long mThrottle;
private boolean mRandomizeThrottle;
public MonkeyEventQueue(Random random, long throttle, boolean randomizeThrottle) {
super();
mRandom = random;
mThrottle = throttle;
mRandomizeThrottle = randomizeThrottle;
}
@Override
public void addLast(MonkeyEvent e) {
super.add(e);
if (e.isThrottlable()) {
long throttle = mThrottle;
if (mRandomizeThrottle && (mThrottle > 0)) {
throttle = mRandom.nextLong();
if (throttle < 0) {
throttle = -throttle;
}
throttle %= mThrottle;
++throttle;
}
super.add(new MonkeyThrottleEvent(throttle));
}
}
}
MonkeyEventQueue继承于LinkedList,并且仅仅重写了addLast方法。
为了保存各种MonkeyEvent。
setFactors方法重新为所占百分比赋值。
public void setFactors(float factors[]) {
int c = FACTORZ_COUNT;
if (factors.length < c) {
c = factors.length;
}
for (int i = 0; i < c; i++)
mFactors[i] = factors[i];
}
generateActivity方法产生Activity事件。
public void generateActivity() {
MonkeyActivityEvent e = new MonkeyActivityEvent(mMainApps.get(
mRandom.nextInt(mMainApps.size())));
mQ.addLast(e);
}
3.2 测试
MonkeySourceRandom的getNextEvent方法如下,
public MonkeyEvent getNextEvent() {
if (mQ.isEmpty()) {
generateEvents();
}
mEventCount++;
MonkeyEvent e = mQ.getFirst();
mQ.removeFirst();
return e;
}
逻辑很简单,从MonkeyEventQueue中取出下一条事件。如果没有,就产生事件。
generateEvents方法如下,产生各种事件。
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;
}
// The remaining event categories are injected as key events
for (;;) {
if (cls < mFactors[FACTOR_NAV]) {
lastKey = NAV_KEYS[mRandom.nextInt(NAV_KEYS.length)];
} else if (cls < mFactors[FACTOR_MAJORNAV]) {
lastKey = MAJOR_NAV_KEYS[mRandom.nextInt(MAJOR_NAV_KEYS.length)];
} else if (cls < mFactors[FACTOR_SYSOPS]) {
lastKey = SYS_KEYS[mRandom.nextInt(SYS_KEYS.length)];
} else if (cls < mFactors[FACTOR_APPSWITCH]) {
MonkeyActivityEvent e = new MonkeyActivityEvent(mMainApps.get(
mRandom.nextInt(mMainApps.size())));
mQ.addLast(e);
return;
} else if (cls < mFactors[FACTOR_FLIP]) {
MonkeyFlipEvent e = new MonkeyFlipEvent(mKeyboardOpen);
mKeyboardOpen = !mKeyboardOpen;
mQ.addLast(e);
return;
} else {
lastKey = 1 + mRandom.nextInt(KeyEvent.getMaxKeyCode() - 1);
}
if (lastKey != KeyEvent.KEYCODE_POWER
&& lastKey != KeyEvent.KEYCODE_ENDCALL
&& lastKey != KeyEvent.KEYCODE_SLEEP
&& PHYSICAL_KEY_EXISTS[lastKey]) {
break;
}
}
MonkeyKeyEvent e = new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, lastKey);
mQ.addLast(e);
e = new MonkeyKeyEvent(KeyEvent.ACTION_UP, lastKey);
mQ.addLast(e);
}
runMonkeyCycles使用while循环调用获取MonkeyEvent然后注入事件。
MonkeyEvent ev = mEventSource.getNextEvent();
if (ev != null) {
int injectCode = ev.injectEvent(mWm, mAm, mVerbose);
终止的条件如下,
while (!systemCrashed && cycleCounter < mCount) {
1,系统已经崩溃
2,重复次数已经到了设置次数。
这样很简单就完成测试了。
4. monkey框架结构
Monkey的代码比较少,结构简单。主要功能分为2块
1,产生事件
2,触发事件
Monkey.java
程序的入口,调度中心,解析参数,构造不同的MonkeyEventSource子类。
MonkeyEventSource.java
4中模式分别对应不同的MonkeyEventSource
例如, MonkeySourceScript/MonkeySourceRandomScript/ MonkeySourceNetwork/ MonkeySourceRandom
MonkeyEvent.java
各种事件的具体实现。如MonkeyKeyEvent/ MonkeyMotionEvent等等。
最后都是调用AM/WM/PM 来实现。