Cts分析框架(4)-添加任务

Debug

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXRmb290YmFsbA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

debug的入口在CtsConsole类,所以我们把第一个断点打在249行:

Console console = new CtsConsole();

按F6再按F5进入到Console.startConsole方法中。

按F5进入GlobalConfiguration.createGlobalConfiguration方法中。

该方法内主要是读取全局配置文件并设置IGlobalConfiguration接口对象sInstance。主要方法为95行读取文件的getGlobalConfigPath():

private static String getGlobalConfigPath() throws ConfigurationException {
        String path = System.getenv(GLOBAL_CONFIG_VARIABLE);
        if (path != null) {
            // don't actually check for accessibility here, since the variable
            // might be specifying
            // a java resource rather than a filename. Even so, this can help
            // the user figure out
            // which global config (if any) was picked up by TF.
            System.err
                    .format("Attempting to use global config \"%s\" from variable $%s.\n",
                            path, GLOBAL_CONFIG_VARIABLE);
            return path;
        }

        File file = new File(GLOBAL_CONFIG_FILENAME);
        if (file.exists()) {
            path = file.getPath();
            System.err.format(
                    "Attempting to use auto detected global config \"%s\".\n",
                    path);
            System.err.flush();
            return path;
        }

        // FIXME: search in tradefed.sh launch dir (or classpath?

)

        return null;
    }

首先推断是否设置了全局配置文件的系统变量,假设没有设置,那直接在当前文件文件夹下找tf_global_config.xml文件

非常显然,本程序这些都没有。所以该方法返回的结果应该是null。回到了createGlobalConfiguration(String[] args)方法中:

if (globalConfigPath != null) {
				// Found a global config file; attempt to parse and use it
				sInstance = configFactory.createGlobalConfigurationFromArgs(
						ArrayUtil.buildArray(new String[] { globalConfigPath },
								args), nonGlobalArgs);
				System.err.format("Success!  Using global config \"%s\"\n",
						globalConfigPath);
			} else {
				// Use default global config
				sInstance = new GlobalConfiguration();
				nonGlobalArgs = Arrays.asList(args);
			}
			return nonGlobalArgs;

由于返回的路径为null。所以直接跳转到else语句块中,new一个新对象,没有设置不论什么属性。最后将命令行參数封装在list中返回,然后console设置參数,终于启动线程来运行任务。所以第二个断点要打在Console的run方法里。然后按F8进入run方法。

run方法中先做一些參数的推断,假设为空。启动CommandScheduler线程。里面会去从运行队列中拿出队首元素。假设取得的队列为空就会结束。

假设參数不为空。除了启动CommandScheduler线程外还会运行其它的操作,例如以下:

public void run() {
        List<String> arrrgs = mMainArgs;
        // Fallback, in case this isn't set already
        if (mScheduler == null) {
            mScheduler = new CommandScheduler();
        }

        try {
            // Check System.console() since jline doesn't seem to consistently know whether or not
            // the console is functional.
            if (!isConsoleFunctional()) {
                if (arrrgs.isEmpty()) {
                    printLine("No commands for non-interactive mode; exiting.");
                    // FIXME: need to run the scheduler here so that the things blocking on it
                    // FIXME: will be released.
                    mScheduler.start();
                    mScheduler.await();
                    return;
                } else {
                    printLine("Non-interactive mode: Running initial command then exiting.");
                    mShouldExit = true;
                }
            }

            // Wait for the CommandScheduler to start.  It will hold the JVM open (since the Console
            // thread is a Daemon thread), and also we require it to have started so that we can
            // start processing user input.
            mScheduler.start();
            mScheduler.await();

            String input = "";
            CaptureList groups = new CaptureList();
            String[] tokens;

            // Note: since Console is a daemon thread, the JVM may exit without us actually leaving
            // this read loop.  This is by design.
            do {
                if (arrrgs.isEmpty()) {
                    input = getConsoleInput();

                    if (input == null) {
                        // Usually the result of getting EOF on the console
                        printLine("");
                        printLine("Received EOF; quitting...");
                        mShouldExit = true;
                        break;
                    }

                    tokens = null;
                    try {
                        tokens = QuotationAwareTokenizer.tokenizeLine(input);
                    } catch (IllegalArgumentException e) {
                        printLine(String.format("Invalid input: %s.", input));
                        continue;
                    }

                    if (tokens == null || tokens.length == 0) {
                        continue;
                    }
                } else {
                    printLine(String.format("Using commandline arguments as starting command: %s",
                            arrrgs));
                    if (mConsoleReader != null) {
                        // Add the starting command as the first item in the console history
                        // FIXME: this will not properly escape commands that were properly escaped
                        // FIXME: on the commandline.  That said, it will still be more convenient
                        // FIXME: than copying by hand.
                        final String cmd = ArrayUtil.join(" ", arrrgs);
                        mConsoleReader.getHistory().addToHistory(cmd);
                    }
                    tokens = arrrgs.toArray(new String[0]);
                    //置空
                    arrrgs = Collections.emptyList();
                }

                Runnable command = mCommandTrie.retrieve(groups, tokens);
                if (command != null) {
                    executeCmdRunnable(command, groups);
                } else {
                    printLine(String.format(
                            "Unable to handle command '%s'.  Enter 'help' for help.", tokens[0]));
                }

                RunUtil.getDefault().sleep(100);
            } while (!mShouldExit);
        } catch (Exception e) {
            printLine("Console received an unexpected exception (shown below); shutting down TF.");
            e.printStackTrace();
        } finally {
            mScheduler.shutdown();
            // Make sure that we don't quit with messages still in the buffers
            System.err.flush();
            System.out.flush();
        }
    }

上面这段代码主要看846行左右的

 executeCmdRunnable(command, groups);

我们来看这种方法里面的实现:

/**
     * Execute a command.
     * <p />
     * Exposed for unit testing
     */
    @SuppressWarnings("unchecked")
    void executeCmdRunnable(Runnable command, CaptureList groups) {
        if (command instanceof ArgRunnable) {
            // FIXME: verify that command implements ArgRunnable<CaptureList> instead
            // FIXME: of just ArgRunnable
            ((ArgRunnable<CaptureList>)command).run(groups);
        } else {
            command.run();
        }
    }

会发现程序会跳转到

((ArgRunnable<CaptureList>)command).run(groups);

然后再按F5就跳转不进去了。这个时候程序进入到了

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXRmb290YmFsbA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

所以在这个地方打个断点。又一次启动debug,会进入到这个地方。该方法调用了CommandScheduler.addCommand方法,进入该方法

/**
     * {@inheritDoc}
     */
    @Override
    public boolean addCommand(String[] args, long totalExecTime) {
        try {
        	//得到cts配置文件的信息
            IConfiguration config = getConfigFactory().createConfigurationFromArgs(args);
            //打印帮助信息,仅仅打印Importance类型的option信息
            if (config.getCommandOptions().isHelpMode()) {
                getConfigFactory().printHelpForConfig(args, true, System.out);
                System.out.flush();
                //打印全部option信息
            } else if (config.getCommandOptions().isFullHelpMode()) {
                getConfigFactory().printHelpForConfig(args, false, System.out);
            } else if (config.getCommandOptions().isDryRunMode()) {
                if (config.getCommandOptions().isNoisyDryRunMode()) {
                    CLog.logAndDisplay(LogLevel.DEBUG, "DRY RUN: %s", Arrays.toString(args));
                } else {
                    CLog.d("Dry run mode; skipping adding command: %s", Arrays.toString(args));
                }
            } else {
                config.validateOptions();

                if (config.getCommandOptions().runOnAllDevices()) {
                    addCommandForAllDevices(totalExecTime, args);
                } else {
                    CommandTracker cmdTracker = createCommandTracker(args);
                    cmdTracker.incrementExecTime(totalExecTime);
                    ExecutableCommand cmdInstance = createExecutableCommand(cmdTracker, config, false);
                    addExecCommandToQueue(cmdInstance, 0);
                }
                return true;
            }
        } catch (ConfigurationException e) {
        	e.printStackTrace();
            // FIXME: do this with jline somehow for ANSI support
            // note: make sure not to log (aka record) this line, as (args) may contain passwords.
            System.out.println(String.format("Error while processing args: %s",
                    Arrays.toString(args)));
            System.out.println(e.getMessage());
            System.out.println();
        }
        return false;
    }

先来看第一行代码:

IConfiguration config = getConfigFactory().createConfigurationFromArgs(args);

该方法会依据參数中的第二个參数来找到config文件夹下的xml文件,读取里面的内容,然后配置CTS框架的9大组件(这个内容放在下一篇文章讲)。

得到Config对象后,会推断是全设备执行还是单个设备执行,默认是全设备执行。假设是单设备执行,须要指定设备的sn号,框架依据SN号来找到设备。最后将执行计划放入到队列中。

到此任务的加入就完毕了。任务队列不断的接受新的任务,然后CommandScheduler的run方法里有一个循环。每次都取第一个任务出来运行。

 try {
            // Notify other threads that we're running.
            mRunLatch.countDown();

            IDeviceManager manager = getDeviceManager();
            while (!isShutdown()) {
                ExecutableCommand cmd = dequeueConfigCommand();
                if (cmd != null) {
                	IDeviceSelection options = cmd.getConfiguration().getDeviceRequirements();
                    ITestDevice device = manager.allocateDevice(0, options);
                    if (device != null) {
                        // Spawn off a thread to perform the invocation
                        InvocationThread invThread = startInvocation(manager, device, cmd);
                        addInvocationThread(invThread);
                        if (cmd.isLoopMode()) {
                            addNewExecCommandToQueue(cmd.getCommandTracker());
                        }
                    } else {
                        // no device available for command, put back in queue
                        // increment exec time to ensure fair scheduling among commands when devices
                        // are scarce
                        cmd.getCommandTracker().incrementExecTime(1);
                        addExecCommandToQueue(cmd, NO_DEVICE_DELAY_TIME);
                        //CLog.logAndDisplay(LogLevel.ERROR,String.format("Can't find device %s.",options.getSerials()));
                    }
                }
            }
            mCommandTimer.shutdown();
            CLog.i("Waiting for invocation threads to complete");
            List<InvocationThread> threadListCopy;
            synchronized (this) {
                threadListCopy = new ArrayList<InvocationThread>(mInvocationThreads.size());
                threadListCopy.addAll(mInvocationThreads);
            }
            for (Thread thread : threadListCopy) {
                waitForThread(thread);
            }
            closeRemoteClient();
            if (mRemoteManager != null) {
                mRemoteManager.cancel();
            }
            exit(manager);
            cleanUp();
            CLog.logAndDisplay(LogLevel.INFO, "All done");
        } finally {
            // Make sure that we don't quit with messages still in the buffers
            System.err.flush();
            System.out.flush();
        }

到此任务的加入就算讲完了。 下一篇文章解析一下是怎样解析配置文件的。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

时间: 2024-08-28 18:14:17

Cts分析框架(4)-添加任务的相关文章

【转】兼容性测试套件(CTS)框架用户手册

原文网址:http://blog.sina.com.cn/s/blog_416166e90102v6bi.html 兼容性测试套件(CTS)框架用户手册 1.为什么需要兼容性测试(以下称CTS)? 2.怎么样才能让我的设备变成兼容的. 2.1.与Android Compatibility Definition文档(以下简称ACD)匹配 2.2.通过CTS测试 2.3.提交报告 3.CTS的工作原理 3.1.工作流程 3.2.测试案例类型 3.3.目前的测试覆盖面 4.设置和使用CTS 4.1.配

符号执行-基于python的二进制分析框架angr

转载:All Right 符号执行概述 在学习这个框架之前首先要知道符号执行.符号执行技术使用符号值代替数字值执行程序,得到的变量的值是由输入变 量的符号值和常量组成的表达式.符号执行技术首先由King在1976年提出 ,经过三十多年的发展,现在仍然被广泛研究,它在软件测试和程序验证中发挥着重 要作用.符号执行是一种重要的形式化方法和静态分析技术,它使用数学和逻辑 首先定义一些基本概念.程序的路径(path)是程序的一个语句序列,这个 语句序列包括程序的一些顺序的代码片段,代码片段之间的连接是由

【转】console.time 简单分析javascript动态添加Dom节点的性能

本文代码约定 1 el: 指的是增加直接点的DOM节点 2 totalNum: 为100000(值越大越能体现差距)指的是循环创建的DOM节点 3 for(var i=0;i<totalNum;i++){}: 我们用for来表示就好了,简写代码 如果叫你用javascript动态增加DOM节点,你有哪几种思路呢? 1 .使用innerHTML和字符串拼接 console.time("time1"); var str = ""; for{ str += &quo

console.time 简单分析javascript动态添加Dom节点的性能

Bullshit 本来想每天都更新下博客的,但是最近要考试,还有就是自己还是停留在暗自窃喜中吧(这种想法要改变).其实最近总在想,自己要怎么去管理自己的数据,每天的生活都是对自己的数据的增删查改.昨天把自己的电脑重装了,确实很多软件的存放要改地方了,之前不知道怎么去管理软件安装,所以放得乱七八糟的.说好一大堆废话之后,我最后再说一遍,管好自己的时间.数据真的比你学习东西重要. Method 本文代码约定 1 el: 指的是增加直接点的DOM节点 2 totalNum: 为100000(值越大越能

Android已有的原生Camera框架中添加自己的API的实现方案。

在过去的2个月里,基本定制并评估完了项目所需要的基本需求,围绕着全志A31和Android4.2.2来实现.最近由于需要,在修改他的Camera的架构中,需要应用程序给HAL透传一个参数来控制底层图像处理算法的实现,即需要提供一个合理的API供APP的开发使用. 起初想到的,最简单有效的方法就是重新定制SDK,但不断遇到的问题,使得最终切换了部分的思路,但核心没有发生变化. Android系统的架构层次分明,在复杂的架构中往往理解以后会变得十分的简单,现在看来,过去2个多月的时间基本把Camer

【j2ee spring】11、整合SSH框架之添加一个成员

11.整合SSH框架之添加一个成员 1.我们写一个天机成员的jsp文件 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD H

关于思维、营销、咨询、绩效管理的一些经典分析框架

关于思维.市场营销.管理咨询.绩效管理等的分析框架有很多很多.即使看过很多框架,在碰到具体场景时也经常没办法下手.但这并不意味着不需要学习框架,因为不同框架有其适用性.多实践,灵活运用,学会搭建自己的分析框架,达到碰到任何场景都能快速搭建分析框架的地步时,你就能如鱼得水了.而这个过程,很长,也很痛苦,也很快乐. 一.思维方面 即普遍适用于任何问题或处事的思维框架,框架虽简单,但也能大致有一些指导作用. 1.1 5W2H 提好的问题是解决问题的一半. 当做思维方面的框架,基本可用于任何场景.可以从

麦肯锡案例分析框架

想进麦肯锡,需要模拟多少个高质量Case? 答案是:50个,如果质量非常高,30个 这是Uni酱调研了30位麦肯锡顾问的结果 是不是很惊悚,你左边的无公害同桌 此时可能正在小黑屋加速练Case 但是真实情况就是有的人过分看重框架 有的人根本不知道所谓的咨询回答 居然还需要一个东西叫做"逻辑框架" 今日重磅福利 微信后台回复"逻辑"即可获得: 文字稿整理麦肯锡分析框架精华版 典藏版Look Over My Shoulder的教学音频 德勤2018笔试面试精华+原创案例

七周成为数据分析师03_业务分析框架

如何建立业务分析框架 从指标的角度出发 从业务的角度出发 从流程的角度出发 1. 市场营销模型 以'潜在客户-机会客户-新客-老客-忠诚客户'为主轴进行扩展. 以"机会客户"为例,可对其进行结构化思维划分: 2. AARRR 模型 付费推广渠道,先下载再注册:社交传播渠道,先注册再下载. 以"二次激活"为例进行扩展: 3. 用户行为模型(内容平台) 4. 电子商务模型 5. 流量模型 6. 如何应对各类业务场景 多加练习 熟悉业务 应用三种核心思维 归纳和整理出指标