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);
}

 

posted @ 2017-02-08 00:36  q55091  阅读(750)  评论(0编辑  收藏  举报