CTS测试框架 -- 命令调度
来源:互联网 发布:paint it black 编辑:程序博客网 时间:2024/06/05 16:14
1.CommandScheduler启动
CommandScheduler本身也是一个线程,是在Console线程启动时启动的,作为命令调度的线程,主要作用就是检查本身的CommandQueue中是不是有需要处理的command,进行调度不至于多命令或者多设备时出现混乱,以及启动真正的命令执行线程。
public void run() { assertStarted(); try { IDeviceManager manager = getDeviceManager(); startRemoteManager(); // 在启动的第一时间先countDown,此时main线程就会被释放,就退出了 mRunLatch.countDown(); // add a listener that will wake up scheduler when a new avail device is added manager.addDeviceMonitor(new AvailDeviceMonitor()); // 进入了循环处理命令,直到输入了退出命令 while (!isShutdown()) { // 每过30s起来看看是不是有需要调度的命令 mCommandProcessWait.waitAndReset(mPollTime); checkInvocations(); processReadyCommands(manager); postProcessReadyCommands(); } // 退出循环之后代表程序即将退出了,进行一些清理工作 mCommandTimer.shutdown(); manager.terminateDeviceRecovery(); manager.terminateDeviceMonitor(); CLog.i("Waiting for invocation threads to complete"); waitForAllInvocationThreads(); closeRemoteClient(); if (mRemoteManager != null) { mRemoteManager.cancelAndWait(); } 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(); }}
2.命令调度
在CommandScheduler的循环中去不断的看是否有新的命令,前面添加命令的时候,有notifyAll,以及上一个命令执行完毕等,当需要有命令被调度时都会有notifyAll去及时唤醒CommandScheduler开始干活。
public synchronized void waitAndReset(long maxWaitTime) { waitForEvent(maxWaitTime); reset();}// 这里是等待命令的逻辑// 大致逻辑就是每过30s就看看是不是有需要调度的命令public synchronized boolean waitForEvent(long maxWaitTime) { if (maxWaitTime == 0) { return waitForEvent(); } long startTime = System.currentTimeMillis(); long remainingTime = maxWaitTime; while (!mEventReceived && remainingTime > 0) { try { wait(remainingTime); } catch (InterruptedException e) { CLog.w("interrupted"); } remainingTime = maxWaitTime - (System.currentTimeMillis() - startTime); } return mEventReceived;}
调度processReadyCommands
protected void processReadyCommands(IDeviceManager manager) { Map<ExecutableCommand, IInvocationContext> scheduledCommandMap = new HashMap<>(); // 命令调度是同步的,但是命令执行不是 // 也就是说在调度符合的情况下,是可以开启多个命令执行的线程的 // 即可以有多条命令同时运行 synchronized (this) { Collections.sort(mReadyCommands, new ExecutableCommandComparator()); Iterator<ExecutableCommand> cmdIter = mReadyCommands.iterator(); while (cmdIter.hasNext()) { // 遍历mReadyCommands取出命令 ExecutableCommand cmd = cmdIter.next(); IConfiguration config = cmd.getConfiguration(); // 创建命令context IInvocationContext context = new InvocationContext(); context.setConfigurationDescriptor(config.getConfigurationDescription()); Map<String, ITestDevice> devices = // 申请设备 allocateDevices(config, manager); // 如果能申请到设备,说明当前命令是可以执行的 if (!devices.isEmpty()) { // 从ready Queue中移除 cmdIter.remove(); // 添加到正在执行的queue mExecutingCommands.add(cmd); context.addAllocatedDevice(devices); // 记录正在执行的命令的map scheduledCommandMap.put(cmd, context); mUnscheduledWarning.remove(cmd); } else { // 没有空闲的设备时提示警告 if (!mUnscheduledWarning.contains(cmd)) { CLog.logAndDisplay(LogLevel.DEBUG, "No available device matching all the " + "config's requirements for cmd id %d.", cmd.getCommandTracker().getId()); System.out.println( String.format( "The command %s will be rescheduled.", Arrays.toString(cmd.getCommandTracker().getArgs()))); mUnscheduledWarning.add(cmd); } } } } // 这里真正开始执行 for (Map.Entry<ExecutableCommand, IInvocationContext> cmdDeviceEntry : scheduledCommandMap .entrySet()) { ExecutableCommand cmd = cmdDeviceEntry.getKey(); // 开启命令执行的新线程去执行命令 startInvocation(cmdDeviceEntry.getValue(), cmd, new FreeDeviceHandler(getDeviceManager())); // 如果命令是循环模式,则再加入队列进行调度 if (cmd.isLoopMode()) { addNewExecCommandToQueue(cmd.getCommandTracker()); } }}
开始执行命令的线程 InvocationThread
private void startInvocation( IInvocationContext context, ExecutableCommand cmd, IScheduledInvocationListener... listeners) { initInvocation(); // Check if device is not used in another invocation. throwIfDeviceInInvocationThread(context.getDevices()); CLog.d("starting invocation for command id %d", cmd.getCommandTracker().getId()); final String invocationName = String.format("Invocation-%s", context.getSerials().get(0)); // 初始化InvocationThread InvocationThread invocationThread = new InvocationThread(invocationName, context, cmd, listeners); logInvocationStartedEvent(cmd.getCommandTracker(), context); // 开启命令执行的线程 invocationThread.start(); addInvocationThread(invocationThread);}
命令执行 InvocationThread.run
InvocationThread类的run方法开始执行,也就代表一个命令的真正执行就开始了,其实命令执行主要还是把前面封装好的Configuration中的组件拿出来,协作运行,主要还是执行其中最重要的test标签下的类中的模板方法,也就是说,test组件虽然是自己实现的,但是是遵循了模板接口的,命令的执行本质就是讲组件取出来协作运行,然后调用模板方法,也就走到了真正test组件的自定义要执行的方法。
在run方法中,其实做的事情不多,就是调用了初始化时创建的TestInvocation对象的invoke方法
instance.invoke(mInvocationContext, config, new Rescheduler(mCmd.getCommandTracker()), mListeners);
组件取出运行都在TestInvocation中,这个类功能很多,承担了整个框架的大部分组件的实际运行。
3.总结
命令的调度CommandScheduler的作用主要负责命令以及设备之间的调度,因为一条命令支持多设备运行,也可以多个设备同时运行不同的命令,必须有一个调度的角色去处理,CommandScheduler通过其内部的几个队列以及获取当前的设备状态完成调度,保证每条命令都能有条不紊的执行。
- CTS测试框架 -- 命令调度
- CTS测试框架 -- 命令解析
- CTS测试框架 -- 命令执行
- CTS测试框架 -- 开篇
- CTS测试框架 -- RegexTrie
- CTS测试框架 -- 总结
- Android cts测试命令
- 自动化测试CTS命令
- CTS测试命令
- CTS测试框架 -- V1版本
- CTS测试框架 -- V2版本
- CTS测试框架 -- 基础框架Trade-Federation
- CTS测试框架 -- 基础框架启动
- Android兼容性测试框架(CTS)手册
- ANDROID兼容性测试框架(CTS)手册
- Android兼容性测试框架(CTS)手册
- Android兼容性测试框架(CTS)手册
- Android兼容性测试框架(CTS)手册
- mysql知识点整理
- mysql文件类型-->查询日志文件
- URAL 1132 Square Root 暴力枚举,二次剩余.
- Linux线程同步笔记
- Qt lnk1158 无法运行rc.exe 解决方法
- CTS测试框架 -- 命令调度
- idea插件的使用
- DOM学习笔记(3)
- Java基础学习总结(2)—Java基本语法1
- 第一篇博客
- DeptSqlProvider(dao)
- Ubuntu/Linux Google chrome 无法打不开
- Java设计模式之简单工厂模式
- Android Studio下编译SDL库的步骤