Monkey 启动原理分析
monkey位于/system/bin目录下。内容为:
# Script to start "monkey" on the device, which has a very rudimentary # shell. # base=/system export CLASSPATH=$base/framework/monkey.jar trap "" HUP exec app_process $base/bin com.android.commands.monkey.Monkey $*
改造内容:
编译安卓源码,改动monkey源码,生成monkey.jar 放在/data目录
export CLASSPATH=/data/monkey.jar
trap "" HUP
exec app_process $base/bin com.android.commands.monkey.Monkey $*
运行命令:/system/bin/sh /data/monkey.jar -p xxxxxx
命令输入启动后进入:
public static void main(String[] args) { // Set the process name showing in "ps" or "top" Process.setArgV0("com.android.commands.monkey"); int resultCode = (new Monkey()).run(args); System.exit(resultCode); }
具体run:运行前的准备
private int run(String[] args) { processOptions();//处理参数 loadPackageLists();//加载黑白名单,可测的有效包名 getSystemInterfaces();//获取系统接口,都是系统的隐藏接口。 //mAm = ActivityManagerNative.getDefault(); //这里返回了一个ActivityManagerProxy对象,用来执行mangerservice接口。 //mWm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); //上面,获取了系统窗口服务 //mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); getMainApps();//获取要执行的activity mEventSource = new MonkeySourceRandom(mRandom, mMainApps, mThrottle, mRandomizeThrottle, mPermissionTargetSystem);//产生一个随机事件 ((MonkeySourceRandom) mEventSource).setFactors(i, mFactors[i]); mEventSource.validate();//验证事件,并调整比例 mNetworkMonitor.start();//监听网络变化 crashedAtCycle = runMonkeyCycles();//monkey核心逻辑 }
重点1:随机事件
下面为默认的分发机制,当日可以通过命令的参数来修改,如果没指定将按默认运行
public MonkeySourceRandom(Random random, ArrayList<ComponentName> MainApps, long throttle, boolean randomizeThrottle, Display display) { // 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] = 47.0f; mFactors[FACTOR_MOTION] = 10.0f; mFactors[FACTOR_TRACKBALL] = 30.0f; mFactors[FACTOR_NAV] = 0.0f; mFactors[FACTOR_MAJORNAV] = 5.0f; mFactors[FACTOR_SYSOPS] = 2.0f; mFactors[FACTOR_APPSWITCH] = 0.0f; mFactors[FACTOR_FLIP] = 1.0f; mFactors[FACTOR_ANYTHING] = 3.0f; mFactors[FACTOR_PINCHZOOM] = 2.0f; mRandom = random; mMainApps = MainApps; mQ = new MonkeyEventQueue(random, throttle, randomizeThrottle); mDisplay = display; }
重点2:获取随机事件后如何点击?
int injectCode = ev.injectEvent(mWm, mAm, mVerbose);
主要是:
InputManager.getInstance().injectInputEvent(me,InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT)) { return MonkeyEvent.INJECT_FAIL;
详细:
@Override public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) { MotionEvent me = getEvent(); if ((verbose > 0 && !mIntermediateNote) || verbose > 1) { StringBuilder msg = new StringBuilder(":Sending "); msg.append(getTypeLabel()).append(" ("); switch (me.getActionMasked()) { case MotionEvent.ACTION_DOWN: msg.append("ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: msg.append("ACTION_MOVE"); break; case MotionEvent.ACTION_UP: msg.append("ACTION_UP"); break; case MotionEvent.ACTION_CANCEL: msg.append("ACTION_CANCEL"); break; case MotionEvent.ACTION_POINTER_DOWN: msg.append("ACTION_POINTER_DOWN ").append(me.getPointerId(me.getActionIndex())); break; case MotionEvent.ACTION_POINTER_UP: msg.append("ACTION_POINTER_UP ").append(me.getPointerId(me.getActionIndex())); break; default: msg.append(me.getAction()); break; } msg.append("):"); int pointerCount = me.getPointerCount(); for (int i = 0; i < pointerCount; i++) { msg.append(" ").append(me.getPointerId(i)); msg.append(":(").append(me.getX(i)).append(",").append(me.getY(i)).append(")"); } System.out.println(msg.toString()); } try { //InputManager.getInstance返回input manager的实例 //Injects an input event into the event system on behalf of an application //注入事件 if (!InputManager.getInstance().injectInputEvent(me, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT)) { return MonkeyEvent.INJECT_FAIL; } } finally { me.recycle(); } return MonkeyEvent.INJECT_SUCCESS; }
MonkeyRotationEvent(旋转屏幕):
public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose)
MonkeyRotationEvent -- 使用iwm.freezeRotation(mRotationDegree);来实现旋转屏幕。
重点3:monkeyresult如何产生
在事件循环点击的时候,每个循环都会监控是否产生了ANR/CRASH
while (!systemCrashed && cycleCounter < mCount) { //检查是否发生了ANR if (mRequestAnrBugreport){ getBugreport("anr_" + mReportProcessName + "_"); mRequestAnrBugreport = false; } //检查系统watchdog是否报告bug if (mRequestWatchdogBugreport) { System.out.println("Print the watchdog report"); getBugreport("anr_watchdog_"); mRequestWatchdogBugreport = false; } //检查是否发生了CRASH if (mRequestAppCrashBugreport){ getBugreport("app_crash" + mReportProcessName + "_"); mRequestAppCrashBugreport = false; } //检查bugreport报告生成 if (mRequestPeriodicBugreport){ getBugreport("Bugreport_"); mRequestPeriodicBugreport = false; } //报告系统信息,ANR时出发 if (mRequestDumpsysMemInfo) { mRequestDumpsysMemInfo = false; shouldReportDumpsysMemInfo = true; } //获取下一个随机时间 MonkeyEvent ev = mEventSource.getNextEvent(); //注入事件 int injectCode = ev.injectEvent(mWm, mAm, mVerbose); }