【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的异常捕获和页面控制。

相关推荐
拥小抱6 小时前
Compose 知识点
android
文章永久免费只为良心6 小时前
Web应用安全与防护_第三章_日志文件包含_从一道 CTFshow 题目讲透「日志投毒型 LFI → RCE」:原理、时序陷阱与全变种攻防手册
android·网络安全·渗透测试·漏洞危害·漏洞描述·日志投毒·红队指南
AIsoft_86896 小时前
学术讲座录音如何整理?录音APP可行吗
android·iphone
Patrick在香港9 小时前
一个斜杠,把毫秒变成十几秒
android·数据库·python·性能优化·正则表达式·回溯·redos
海雅达手持终端PDA10 小时前
工业手持终端的“去手机化”演进:看海雅达如何以“同轴扫摄”终结工程妥协,重塑工业PDA新范式
android·物联网·智能手机·硬件工程·能源·制造·iot
booboosui11 小时前
删掉一个住在本机的 agent:8 处要清,顺序不能反
android
hcgeng11 小时前
Android获取崩溃日志
android
aqi0011 小时前
AI编程让鸿蒙开发电子书APP更加快捷
android·华为·harmonyos·鸿蒙·harmony
GY-9312 小时前
【Android】Android Studio 中的协程
android