<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # Debug ![](https://box.kancloud.cn/2016-01-09_56911dc95ba51.jpg) debug的入口在CtsConsole類,所以我們把第一個斷點打在249行: ~~~ Console console = new CtsConsole(); ~~~ 按F6再按F5進入到Console.startConsole方法中。 ![](https://box.kancloud.cn/2016-01-09_56911dc99ecf3.jpg) 按F5進入GlobalConfiguration.createGlobalConfiguration方法中。 ![](https://box.kancloud.cn/2016-01-09_56911dca00f6c.jpg) 該方法內主要是讀取全局配置文件并設置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方法。 ![](https://box.kancloud.cn/2016-01-09_56911dca49e6e.jpg) 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)command).run(groups); ~~~ 然后再按F5就跳轉不進去了,這個時候程序進入到了 ![](https://box.kancloud.cn/2016-01-09_56911dca9b391.jpg) 所以在這個地方打個斷點,重新啟動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號來找到設備。最后將執行計劃放入到隊列中。 ![](https://box.kancloud.cn/2016-01-09_56911dcacc868.jpg) 到此任務的添加就完成了。任務隊列不斷的接受新的任務,然后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(); } ~~~ 到此任務的添加就算講完了,?[下一篇文章](http://blog.csdn.net/itfootball/article/details/com.android.cts.tradefed.result.IssueReporter@b279f3]%7D)解析一下是如何解析配置文件的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看