CTS-任务添加

Debug



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


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Console console = new CtsConsole();  


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




按F5进入GlobalConfiguration.createGlobalConfiguration方法中。




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


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private static String getGlobalConfigPath() throws ConfigurationException {  
  2.         String path = System.getenv(GLOBAL_CONFIG_VARIABLE);  
  3.         if (path != null) {  
  4.             // don't actually check for accessibility here, since the variable  
  5.             // might be specifying  
  6.             // a java resource rather than a filename. Even so, this can help  
  7.             // the user figure out  
  8.             // which global config (if any) was picked up by TF.  
  9.             System.err  
  10.                     .format("Attempting to use global config \"%s\" from variable $%s.\n",  
  11.                             path, GLOBAL_CONFIG_VARIABLE);  
  12.             return path;  
  13.         }  
  14.   
  15.         File file = new File(GLOBAL_CONFIG_FILENAME);  
  16.         if (file.exists()) {  
  17.             path = file.getPath();  
  18.             System.err.format(  
  19.                     "Attempting to use auto detected global config \"%s\".\n",  
  20.                     path);  
  21.             System.err.flush();  
  22.             return path;  
  23.         }  
  24.   
  25.         // FIXME: search in tradefed.sh launch dir (or classpath?)  
  26.   
  27.         return null;  
  28.     }  

首先判断是否设置了全局配置文件的系统变量,如果没有设置,那直接在当前文件目录下找tf_global_config.xml文件 。很显然,本程序这些都没有,所以该方法返回的结果应该是null。回到了createGlobalConfiguration(String[] args)方法中:


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. if (globalConfigPath != null) {  
  2.                 // Found a global config file; attempt to parse and use it  
  3.                 sInstance = configFactory.createGlobalConfigurationFromArgs(  
  4.                         ArrayUtil.buildArray(new String[] { globalConfigPath },  
  5.                                 args), nonGlobalArgs);  
  6.                 System.err.format("Success!  Using global config \"%s\"\n",  
  7.                         globalConfigPath);  
  8.             } else {  
  9.                 // Use default global config  
  10.                 sInstance = new GlobalConfiguration();  
  11.                 nonGlobalArgs = Arrays.asList(args);  
  12.             }  
  13.             return nonGlobalArgs;  

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




run方法中先做一些参数的判断,如果为空,启动CommandScheduler线程,里面会去从执行队列中拿出队首元素,如果取得的队列为空就会结束。

如果参数不为空,除了启动CommandScheduler线程外还会执行其他的操作,如下:


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void run() {  
  2.         List<String> arrrgs = mMainArgs;  
  3.         // Fallback, in case this isn't set already  
  4.         if (mScheduler == null) {  
  5.             mScheduler = new CommandScheduler();  
  6.         }  
  7.   
  8.         try {  
  9.             // Check System.console() since jline doesn't seem to consistently know whether or not  
  10.             // the console is functional.  
  11.             if (!isConsoleFunctional()) {  
  12.                 if (arrrgs.isEmpty()) {  
  13.                     printLine("No commands for non-interactive mode; exiting.");  
  14.                     // FIXME: need to run the scheduler here so that the things blocking on it  
  15.                     // FIXME: will be released.  
  16.                     mScheduler.start();  
  17.                     mScheduler.await();  
  18.                     return;  
  19.                 } else {  
  20.                     printLine("Non-interactive mode: Running initial command then exiting.");  
  21.                     mShouldExit = true;  
  22.                 }  
  23.             }  
  24.   
  25.             // Wait for the CommandScheduler to start.  It will hold the JVM open (since the Console  
  26.             // thread is a Daemon thread), and also we require it to have started so that we can  
  27.             // start processing user input.  
  28.             mScheduler.start();  
  29.             mScheduler.await();  
  30.   
  31.             String input = "";  
  32.             CaptureList groups = new CaptureList();  
  33.             String[] tokens;  
  34.   
  35.             // Note: since Console is a daemon thread, the JVM may exit without us actually leaving  
  36.             // this read loop.  This is by design.  
  37.             do {  
  38.                 if (arrrgs.isEmpty()) {  
  39.                     input = getConsoleInput();  
  40.   
  41.                     if (input == null) {  
  42.                         // Usually the result of getting EOF on the console  
  43.                         printLine("");  
  44.                         printLine("Received EOF; quitting...");  
  45.                         mShouldExit = true;  
  46.                         break;  
  47.                     }  
  48.   
  49.                     tokens = null;  
  50.                     try {  
  51.                         tokens = QuotationAwareTokenizer.tokenizeLine(input);  
  52.                     } catch (IllegalArgumentException e) {  
  53.                         printLine(String.format("Invalid input: %s.", input));  
  54.                         continue;  
  55.                     }  
  56.   
  57.                     if (tokens == null || tokens.length == 0) {  
  58.                         continue;  
  59.                     }  
  60.                 } else {  
  61.                     printLine(String.format("Using commandline arguments as starting command: %s",  
  62.                             arrrgs));  
  63.                     if (mConsoleReader != null) {  
  64.                         // Add the starting command as the first item in the console history  
  65.                         // FIXME: this will not properly escape commands that were properly escaped  
  66.                         // FIXME: on the commandline.  That said, it will still be more convenient  
  67.                         // FIXME: than copying by hand.  
  68.                         final String cmd = ArrayUtil.join(" ", arrrgs);  
  69.                         mConsoleReader.getHistory().addToHistory(cmd);  
  70.                     }  
  71.                     tokens = arrrgs.toArray(new String[0]);  
  72.                     //置空  
  73.                     arrrgs = Collections.emptyList();  
  74.                 }  
  75.   
  76.                 Runnable command = mCommandTrie.retrieve(groups, tokens);  
  77.                 if (command != null) {  
  78.                     executeCmdRunnable(command, groups);  
  79.                 } else {  
  80.                     printLine(String.format(  
  81.                             "Unable to handle command '%s'.  Enter 'help' for help.", tokens[0]));  
  82.                 }  
  83.   
  84.                 RunUtil.getDefault().sleep(100);  
  85.             } while (!mShouldExit);  
  86.         } catch (Exception e) {  
  87.             printLine("Console received an unexpected exception (shown below); shutting down TF.");  
  88.             e.printStackTrace();  
  89.         } finally {  
  90.             mScheduler.shutdown();  
  91.             // Make sure that we don't quit with messages still in the buffers  
  92.             System.err.flush();  
  93.             System.out.flush();  
  94.         }  
  95.     }  

 

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

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. executeCmdRunnable(command, groups);  


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


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * Execute a command. 
  3.      * <p /> 
  4.      * Exposed for unit testing 
  5.      */  
  6.     @SuppressWarnings("unchecked")  
  7.     void executeCmdRunnable(Runnable command, CaptureList groups) {  
  8.         if (command instanceof ArgRunnable) {  
  9.             // FIXME: verify that command implements ArgRunnable<CaptureList> instead  
  10.             // FIXME: of just ArgRunnable  
  11.             ((ArgRunnable<CaptureList>)command).run(groups);  
  12.         } else {  
  13.             command.run();  
  14.         }  
  15.     }  

会发现程序会跳转到


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ((ArgRunnable<CaptureList>)command).run(groups);  

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




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


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * {@inheritDoc} 
  3.      */  
  4.     @Override  
  5.     public boolean addCommand(String[] args, long totalExecTime) {  
  6.         try {  
  7.             //得到cts配置文件的信息  
  8.             IConfiguration config = getConfigFactory().createConfigurationFromArgs(args);  
  9.             //打印帮助信息,只打印Importance类型的option信息  
  10.             if (config.getCommandOptions().isHelpMode()) {  
  11.                 getConfigFactory().printHelpForConfig(args, true, System.out);  
  12.                 System.out.flush();  
  13.                 //打印所有option信息  
  14.             } else if (config.getCommandOptions().isFullHelpMode()) {  
  15.                 getConfigFactory().printHelpForConfig(args, false, System.out);  
  16.             } else if (config.getCommandOptions().isDryRunMode()) {  
  17.                 if (config.getCommandOptions().isNoisyDryRunMode()) {  
  18.                     CLog.logAndDisplay(LogLevel.DEBUG, "DRY RUN: %s", Arrays.toString(args));  
  19.                 } else {  
  20.                     CLog.d("Dry run mode; skipping adding command: %s", Arrays.toString(args));  
  21.                 }  
  22.             } else {  
  23.                 config.validateOptions();  
  24.   
  25.                 if (config.getCommandOptions().runOnAllDevices()) {  
  26.                     addCommandForAllDevices(totalExecTime, args);  
  27.                 } else {  
  28.                     CommandTracker cmdTracker = createCommandTracker(args);  
  29.                     cmdTracker.incrementExecTime(totalExecTime);  
  30.                     ExecutableCommand cmdInstance = createExecutableCommand(cmdTracker, config, false);  
  31.                     addExecCommandToQueue(cmdInstance, 0);  
  32.                 }  
  33.                 return true;  
  34.             }  
  35.         } catch (ConfigurationException e) {  
  36.             e.printStackTrace();  
  37.             // FIXME: do this with jline somehow for ANSI support  
  38.             // note: make sure not to log (aka record) this line, as (args) may contain passwords.  
  39.             System.out.println(String.format("Error while processing args: %s",  
  40.                     Arrays.toString(args)));  
  41.             System.out.println(e.getMessage());  
  42.             System.out.println();  
  43.         }  
  44.         return false;  
  45.     }  

先来看第一行代码:


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. IConfiguration config = getConfigFactory().createConfigurationFromArgs(args);  

该方法会根据参数中的第二个参数来找到config目录下的xml文件,读取里面的内容,然后配置CTS框架的9大组件(这个内容放在下一篇文章讲)。得到Config对象后,会判断是全设备运行还是单个设备运行,默认是全设备运行。如果是单设备运行,需要指定设备的sn号,框架根据SN号来找到设备。最后将执行计划放入到队列中。




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


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. try {  
  2.            // Notify other threads that we're running.  
  3.            mRunLatch.countDown();  
  4.              
  5.            IDeviceManager manager = getDeviceManager();  
  6.            while (!isShutdown()) {  
  7.                ExecutableCommand cmd = dequeueConfigCommand();  
  8.                if (cmd != null) {  
  9.                 IDeviceSelection options = cmd.getConfiguration().getDeviceRequirements();  
  10.                    ITestDevice device = manager.allocateDevice(0, options);  
  11.                    if (device != null) {  
  12.                        // Spawn off a thread to perform the invocation  
  13.                        InvocationThread invThread = startInvocation(manager, device, cmd);  
  14.                        addInvocationThread(invThread);  
  15.                        if (cmd.isLoopMode()) {  
  16.                            addNewExecCommandToQueue(cmd.getCommandTracker());  
  17.                        }  
  18.                    } else {  
  19.                        // no device available for command, put back in queue  
  20.                        // increment exec time to ensure fair scheduling among commands when devices  
  21.                        // are scarce  
  22.                        cmd.getCommandTracker().incrementExecTime(1);  
  23.                        addExecCommandToQueue(cmd, NO_DEVICE_DELAY_TIME);  
  24.                        //CLog.logAndDisplay(LogLevel.ERROR,String.format("Can't find device %s.",options.getSerials()));  
  25.                    }  
  26.                }  
  27.            }  
  28.            mCommandTimer.shutdown();  
  29.            CLog.i("Waiting for invocation threads to complete");  
  30.            List<InvocationThread> threadListCopy;  
  31.            synchronized (this) {  
  32.                threadListCopy = new ArrayList<InvocationThread>(mInvocationThreads.size());  
  33.                threadListCopy.addAll(mInvocationThreads);  
  34.            }  
  35.            for (Thread thread : threadListCopy) {  
  36.                waitForThread(thread);  
  37.            }  
  38.            closeRemoteClient();  
  39.            if (mRemoteManager != null) {  
  40.                mRemoteManager.cancel();  
  41.            }  
  42.            exit(manager);  
  43.            cleanUp();  
  44.            CLog.logAndDisplay(LogLevel.INFO, "All done");  
  45.        } finally {  
  46.            // Make sure that we don't quit with messages still in the buffers  
  47.            System.err.flush();  
  48.            System.out.flush();  
  49.        }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值