• 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);
    }
  • 相关阅读:
    MySQL与Redis结合方案
    Linux系统如何监控服务器硬件、操作系统、应用服务和业务
    【MySQL】MySQL复制之防崩溃从节点
    Linux系统vim编辑器换行至文件的行首及行尾操作
    Xtrabackup远程备份
    innodb_force_recovery参数分析
    Oracle异构平台迁移利器之XTTS(使用rman方式)
    ES6基础语法
    读郭老师推荐书籍--《原则》
    PhpStorm 的基本应用
  • 原文地址:https://www.cnblogs.com/season-xie/p/6376467.html
Copyright © 2020-2023  润新知