【Android Monkey源码解析三】- 运行解析

今天,承接上文 【Android Monkey源码解析二】- 参数解析 中提到的Monkey主类进行继续解析。

java 复制代码
/**
 * Run the command!
 *
 * @param args The command-line arguments
 * @return Returns a posix-style result code. 0 for no error.
 */
private int run(String[] args) {

    ...

    // now set up additional data in preparation for launch
    // 如果在命令行参数中没有指定category(-c)的情况下,添加CATEGORY_LAUNCHER和CATEGORY_MONKEY
    if (mMainCategories.size() == 0) {
        mMainCategories.add(Intent.CATEGORY_LAUNCHER);
        mMainCategories.add(Intent.CATEGORY_MONKEY);
    }
    // 如果没有设置随机种子值,则自动生成
    if (mSeed == 0) {
        mSeed = System.currentTimeMillis() + System.identityHashCode(this);
    }
    if (mVerbose > 0) {
        // 打印所有的包信息和Category信息
        Logger.out.println(":Monkey: seed=" + mSeed + " count=" + mCount);
        MonkeyUtils.getPackageFilter().dump();
        if (mMainCategories.size() != 0) {
            Iterator<String> it = mMainCategories.iterator();
            while (it.hasNext()) {
                Logger.out.println(":IncludeCategory: " + it.next());
            }
        }
    }
    // 这个目前没有使用到,在此类中,没有任何的逻辑,都是直接返回true
    if (!checkInternalConfiguration()) {
        return -2;
    }
    // 如果获取ActivityManager,WindowManager,PackageManager系统接口对象出现异常,就直接退出
    if (!getSystemInterfaces()) {
        return -3;
    }
    // 此方法的处理,主要是通过Intent结合ACTION_MAIN和通过命令行设置的categories或默认的categories,
    // 获取手机系统上所有满足条件的应用集合;然后,再跟设置的MonkeyUtils中设置的validPackages进行对比
    // 过滤,若过滤后仍没有交集,则程序直接退出;若有满足的条件,则添加到mMainApps集合对象中。
    if (!getMainApps()) {
        return -4;
    }
    // 初始化Random对象,以供后续的随机事件调用
    mRandom = new Random(mSeed);
    // 如果命令行指令有设置Monkey的脚本参数,则进入此逻辑处理
    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) {
        // 如果命令行指令有设置多个Monkey的脚本参数,则进入此逻辑处理
        if (mSetupFileName != null) {
            mEventSource = new MonkeySourceRandomScript(mSetupFileName,
                    mScriptFileNames, mThrottle, mRandomizeThrottle, mRandom,
                    mProfileWaitTime, mDeviceSleepTime, mRandomizeScript);
            mCount++;
        } else {
            mEventSource = new MonkeySourceRandomScript(mScriptFileNames,
                    mThrottle, mRandomizeThrottle, mRandom,
                    mProfileWaitTime, mDeviceSleepTime, mRandomizeScript);
        }
        mEventSource.setVerbose(mVerbose);
        mCountEvents = false;
    } else if (mServerPort != -1) {
        // 如果是服务模式,则进入此处理逻辑
        try {
            mEventSource = new MonkeySourceNetwork(mServerPort);
        } catch (IOException e) {
            Logger.out.println("Error binding to network socket.");
            return -5;
        }
        mCount = Integer.MAX_VALUE;
    } else {
        // random source by default 如果不是上面三种情况,则进入默认的随机事件模式
        if (mVerbose >= 2) { // check seeding performance
            Logger.out.println("// Seeded: " + mSeed);
        }
        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
        // 首先,生成一个随机的Activity启动事件
        ((MonkeySourceRandom) mEventSource).generateActivity();
    }
    // validate source generator
    if (!mEventSource.validate()) {
        return -5;
    }
    // If we're profiling, do it immediately before/after the main monkey
    // loop
    if (mGenerateHprof) {
        signalPersistentProcesses();
    }
    mNetworkMonitor.start();
    int crashedAtCycle = 0;
    try {
        // 执行Monkey循环事件
        crashedAtCycle = runMonkeyCycles();
    } finally {
        // Release the rotation lock if it's still held and restore the
        // original orientation.
        new MonkeyRotationEvent(Surface.ROTATION_0, false).injectEvent(
            mWm, mAm, mVerbose);
    }
    mNetworkMonitor.stop();
    synchronized (this) {
        if (mRequestAnrTraces) {
            reportAnrTraces();
            mRequestAnrTraces = false;
        }
        if (mRequestAnrBugreport){
            Logger.out.println("Print the anr report");
            getBugreport("anr_" + mReportProcessName + "_");
            mRequestAnrBugreport = false;
        }
        if (mRequestWatchdogBugreport) {
            Logger.out.println("Print the watchdog report");
            getBugreport("anr_watchdog_");
            mRequestWatchdogBugreport = false;
        }
        if (mRequestAppCrashBugreport){
            getBugreport("app_crash" + mReportProcessName + "_");
            mRequestAppCrashBugreport = false;
        }
        if (mRequestDumpsysMemInfo) {
            reportDumpsysMemInfo();
            mRequestDumpsysMemInfo = false;
        }
        if (mRequestPeriodicBugreport){
            getBugreport("Bugreport_");
            mRequestPeriodicBugreport = false;
        }
        if (mWatchdogWaiting) {
            mWatchdogWaiting = false;
            notifyAll();
        }
    }
    if (mGenerateHprof) {
        signalPersistentProcesses();
        if (mVerbose > 0) {
            Logger.out.println("// Generated profiling reports in /data/misc");
        }
    }
    // 取消ActivityController的设置
    try {
        mAm.setActivityController(null, true);
        mNetworkMonitor.unregister(mAm);
    } catch (RemoteException e) {
        // just in case this was latent (after mCount cycles), make sure
        // we report it
        if (crashedAtCycle >= mCount) {
            crashedAtCycle = mCount - 1;
        }
    }
    // report dropped event stats
    if (mVerbose > 0) {
        Logger.out.println(":Dropped: keys=" + mDroppedKeyEvents
                + " pointers=" + mDroppedPointerEvents
                + " trackballs=" + mDroppedTrackballEvents
                + " flips=" + mDroppedFlipEvents
                + " rotations=" + mDroppedRotationEvents);
    }
    // report network stats
    mNetworkMonitor.dump();
    if (crashedAtCycle < mCount - 1) {
        Logger.err.println("** System appears to have crashed at event " + crashedAtCycle
                + " of " + mCount + " using seed " + mSeed);
        return crashedAtCycle;
    } else {
        if (mVerbose > 0) {
            Logger.out.println("// Monkey finished");
        }
        return 0;
    }
}

getSystemInterfaces方法通过远程调用的方式,分别获取系统的接口对象ActivityManager(mAm,后续用于判断和控制Activity的进入,主要通过设置ActivityController来实现),WindowManager(mWm ,用于处理输入等),PackageManager(mPm,获取包相关的信息 ):

java 复制代码
/**
 * Attach to the required system interfaces.
 *
 * @return Returns true if all system interfaces were available.
 */
private boolean getSystemInterfaces() {
    mAm = ActivityManager.getService();
    if (mAm == null) {
        Logger.err.println("** Error: Unable to connect to activity manager; is the system "
                + "running?");
        return false;
    }
    mWm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
    if (mWm == null) {
        Logger.err.println("** Error: Unable to connect to window manager; is the system "
                + "running?");
        return false;
    }
    mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
    if (mPm == null) {
        Logger.err.println("** Error: Unable to connect to package manager; is the system "
                + "running?");
        return false;
    }
    try {
        mAm.setActivityController(new ActivityController(), true);
        mNetworkMonitor.register(mAm);
    } catch (RemoteException e) {
        Logger.err.println("** Failed talking with activity manager!");
        return false;
    }
    return true;
}

后续,我们将首先分析Monkey的异常捕获和页面控制。

相关推荐
KevinWang_4 小时前
Android 的 assets 资源和 raw 资源有什么区别?
android
码农幻想梦5 小时前
2021Android从零入门到实战(慕课网官方账号)
android
Jomurphys5 小时前
Android 架构 - 组件化 Modularzation
android
明明明h5 小时前
【Unity3D】Android App Bundle(aab)打包上架Google Play介绍
android
花卷HJ5 小时前
Android 通用 RecyclerView Adapter 实现(支持 ViewBinding + 泛型 + 点击事件)
android
oMcLin5 小时前
如何在Ubuntu 22.04 LTS上配置并优化MySQL 8.0分区表,提高大规模数据集查询的效率与性能?
android·mysql·ubuntu
幸福的达哥6 小时前
安卓APP代码覆盖率测试方案
android·代码覆盖率
佛系打工仔6 小时前
绘制K线入门
android
川石课堂软件测试8 小时前
Android和iOS APP平台测试的区别
android·数据库·ios·oracle·单元测试·测试用例·cocoa