1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tradefed.command; 18 19 import com.android.tradefed.clearcut.ClearcutClient; 20 import com.android.tradefed.command.CommandRunner.ExitCode; 21 import com.android.tradefed.config.ConfigurationException; 22 import com.android.tradefed.config.IConfigurationFactory; 23 import com.android.tradefed.device.FreeDeviceState; 24 import com.android.tradefed.device.ITestDevice; 25 import com.android.tradefed.device.NoDeviceException; 26 import com.android.tradefed.invoker.IInvocationContext; 27 import com.android.tradefed.invoker.ITestInvocation; 28 import com.android.tradefed.result.ITestInvocationListener; 29 import com.android.tradefed.util.Pair; 30 31 import java.io.PrintWriter; 32 import java.util.List; 33 import java.util.Map; 34 35 /** 36 * A scheduler for running TradeFederation commands. 37 */ 38 public interface ICommandScheduler { 39 40 /** 41 * Listener for invocation events when invocation completes. 42 * @see #execCommand(IScheduledInvocationListener, String[]) 43 */ 44 public static interface IScheduledInvocationListener extends ITestInvocationListener { 45 /** 46 * Callback when an invocation is initiated. This is called before any builds are fetched. 47 * 48 * @param context 49 */ invocationInitiated(IInvocationContext context)50 public default void invocationInitiated(IInvocationContext context) {} 51 52 /** 53 * Callback associated with {@link ICommandOptions#earlyDeviceRelease()} to release the 54 * devices when done with them. 55 * 56 * @param context 57 * @param devicesStates 58 */ releaseDevices( IInvocationContext context, Map<ITestDevice, FreeDeviceState> devicesStates)59 public default void releaseDevices( 60 IInvocationContext context, Map<ITestDevice, FreeDeviceState> devicesStates) {} 61 62 /** 63 * Callback when entire invocation has completed, including all {@link 64 * ITestInvocationListener#invocationEnded(long)} events. 65 * 66 * @param context 67 * @param devicesStates 68 */ invocationComplete( IInvocationContext context, Map<ITestDevice, FreeDeviceState> devicesStates)69 public void invocationComplete( 70 IInvocationContext context, Map<ITestDevice, FreeDeviceState> devicesStates); 71 } 72 73 /** 74 * Adds a command to the scheduler. 75 * 76 * <p>A command is essentially an instance of a configuration to run and its associated 77 * arguments. 78 * 79 * <p>If "--help" argument is specified the help text for the config will be outputed to stdout. 80 * Otherwise, the config will be added to the queue to run. 81 * 82 * @param args the config arguments. 83 * @return A pair of values, first value is a Boolean <code>true</code> if command was added 84 * successfully. Second value is the known command tracker id(non-negative value) if the 85 * command was added successfully, return 0 when command is added for all devices, otherwise 86 * -1. 87 * @throws ConfigurationException if command could not be parsed 88 * @see IConfigurationFactory#createConfigurationFromArgs(String[]) 89 */ addCommand(String[] args)90 public Pair<Boolean, Integer> addCommand(String[] args) throws ConfigurationException; 91 92 /** 93 * Adds all commands from given file to the scheduler 94 * 95 * @param cmdFile the filesystem path of comand file 96 * @param extraArgs a {@link List} of {@link String} arguments to append to each command parsed 97 * from file. Can be empty but should not be null. 98 * @throws ConfigurationException if command file could not be parsed 99 * @see CommandFileParser 100 */ addCommandFile(String cmdFile, List<String> extraArgs)101 public void addCommandFile(String cmdFile, List<String> extraArgs) 102 throws ConfigurationException; 103 104 /** 105 * Directly allocates a device and executes a command without adding it to the command queue. 106 * 107 * @param listener the {@link ICommandScheduler.IScheduledInvocationListener} to be informed 108 * @param args the command arguments 109 * @return The invocation id of the scheduled command. 110 * @throws ConfigurationException if command was invalid 111 * @throws NoDeviceException if there is no device to use 112 */ execCommand(IScheduledInvocationListener listener, String[] args)113 public long execCommand(IScheduledInvocationListener listener, String[] args) 114 throws ConfigurationException, NoDeviceException; 115 116 /** 117 * Directly execute command on already allocated devices. 118 * 119 * @param listener the {@link ICommandScheduler.IScheduledInvocationListener} to be informed 120 * @param devices the {@link List<ITestDevice>} to use 121 * @param args the command arguments 122 * @return The invocation id of the scheduled command. 123 * @throws ConfigurationException if command was invalid 124 */ execCommand( IScheduledInvocationListener listener, List<ITestDevice> devices, String[] args)125 public long execCommand( 126 IScheduledInvocationListener listener, List<ITestDevice> devices, String[] args) 127 throws ConfigurationException; 128 129 /** 130 * Directly execute command on already allocated device. 131 * 132 * @param listener the {@link ICommandScheduler.IScheduledInvocationListener} to be informed 133 * @param device the {@link ITestDevice} to use 134 * @param args the command arguments 135 * @return The invocation id of the scheduled command. 136 * @throws ConfigurationException if command was invalid 137 */ execCommand( IScheduledInvocationListener listener, ITestDevice device, String[] args)138 public long execCommand( 139 IScheduledInvocationListener listener, ITestDevice device, String[] args) 140 throws ConfigurationException; 141 142 /** 143 * Directly allocates a device and executes a command without adding it to the command queue 144 * using an already existing {@link IInvocationContext}. 145 * 146 * @param context an existing {@link IInvocationContext}. 147 * @param listener the {@link ICommandScheduler.IScheduledInvocationListener} to be informed 148 * @param args the command arguments 149 * @throws ConfigurationException if command was invalid 150 * @throws NoDeviceException if there is no device to use 151 */ execCommand( IInvocationContext context, IScheduledInvocationListener listener, String[] args)152 public long execCommand( 153 IInvocationContext context, IScheduledInvocationListener listener, String[] args) 154 throws ConfigurationException, NoDeviceException; 155 156 /** 157 * Remove all commands from scheduler 158 */ removeAllCommands()159 public void removeAllCommands(); 160 161 /** 162 * Attempt to gracefully shutdown the command scheduler. 163 * 164 * <p>Clears commands waiting to be tested, and requests that all invocations in progress shut 165 * down gracefully. 166 * 167 * <p>After shutdown is called, the scheduler main loop will wait for all invocations in 168 * progress to complete before exiting completely. 169 */ shutdown()170 default void shutdown() { 171 shutdown(false); 172 } 173 174 /** 175 * Stops scheduling and accepting new tests but does not stop Tradefed. This is meant to enable 176 * a two steps shutdown where first we drain all the running tests, then terminate Tradefed 177 * process. 178 */ stopScheduling()179 default void stopScheduling() { 180 // Empty 181 } 182 183 /** 184 * Attempt to gracefully shutdown the command scheduler. 185 * 186 * @param notifyStop if true, notifies invocations of TF shutdown. 187 */ shutdown(boolean notifyStop)188 public void shutdown(boolean notifyStop); 189 190 /** 191 * Similar to {@link #shutdown()}, but will instead wait for all commands to be executed 192 * before exiting. 193 * <p/> 194 * Note that if any commands are in loop mode, the scheduler will never exit. 195 */ shutdownOnEmpty()196 public void shutdownOnEmpty(); 197 198 /** Attempt to forcefully shutdown the command scheduler. Same as shutdownHard(true). */ shutdownHard()199 public void shutdownHard(); 200 201 /** 202 * Attempt to forcefully shutdown the command scheduler. 203 * 204 * <p>Similar to {@link #shutdown()}, but will also optionally kill the adb connection, in an 205 * attempt to 'inspire' invocations in progress to complete quicker. 206 */ shutdownHard(boolean killAdb)207 public void shutdownHard(boolean killAdb); 208 209 /** 210 * Start the {@link ICommandScheduler}. 211 * <p/> 212 * Must be called before calling other methods. 213 * <p/> 214 * Will run until {@link #shutdown()} is called. 215 * 216 * see {@link Thread#start()}. 217 */ start()218 public void start(); 219 220 /** 221 * Waits for scheduler to complete. 222 * 223 * @see Thread#join() 224 */ join()225 public void join() throws InterruptedException; 226 227 /** 228 * Waits for scheduler to complete or timeout after the duration specified in milliseconds. 229 * 230 * @see Thread#join(long) 231 */ join(long millis)232 public void join(long millis) throws InterruptedException; 233 234 /** 235 * Waits for scheduler to start running, including waiting for handover from old TF to complete 236 * if applicable. 237 */ await()238 public void await() throws InterruptedException; 239 240 /** 241 * Displays a list of current invocations. 242 * 243 * @param printWriter the {@link PrintWriter} to output to. 244 */ displayInvocationsInfo(PrintWriter printWriter)245 public void displayInvocationsInfo(PrintWriter printWriter); 246 247 /** 248 * Stop a running invocation. 249 * 250 * @return true if the invocation was stopped, false otherwise 251 * @throws UnsupportedOperationException if the implementation doesn't support this 252 */ stopInvocation(ITestInvocation invocation)253 public boolean stopInvocation(ITestInvocation invocation) throws UnsupportedOperationException; 254 255 /** 256 * Stop a running invocation by specifying it's id. 257 * 258 * @return true if the invocation was stopped, false otherwise 259 * @throws UnsupportedOperationException if the implementation doesn't support this 260 */ stopInvocation(int invocationId)261 public default boolean stopInvocation(int invocationId) throws UnsupportedOperationException { 262 return stopInvocation(invocationId, null); 263 } 264 265 /** 266 * Stop a running invocation by specifying it's id. 267 * 268 * @param invocationId the tracking id of the invocation. 269 * @param cause the cause for stopping the invocation. 270 * @return true if the invocation was stopped, false otherwise 271 * @throws UnsupportedOperationException if the implementation doesn't support this 272 */ stopInvocation(int invocationId, String cause)273 public boolean stopInvocation(int invocationId, String cause) 274 throws UnsupportedOperationException; 275 276 /** 277 * Return the information on an invocation bu specifying the invocation id. 278 * 279 * @param invocationId the tracking id of the invocation. 280 * @return A {@link String} containing information about the invocation. 281 */ getInvocationInfo(int invocationId)282 public String getInvocationInfo(int invocationId); 283 284 /** 285 * Output a list of current commands. 286 * 287 * @param printWriter the {@link PrintWriter} to output to. 288 * @param regex the regular expression to which commands should be matched in order to be 289 * printed. If null, then all commands will be printed. 290 */ displayCommandsInfo(PrintWriter printWriter, String regex)291 public void displayCommandsInfo(PrintWriter printWriter, String regex); 292 293 /** 294 * Dump the expanded xml file for the command with all 295 * {@link com.android.tradefed.config.Option} values specified for all current commands. 296 * 297 * @param printWriter the {@link PrintWriter} to output the status to. 298 * @param regex the regular expression to which commands should be matched in order for the 299 * xml file to be dumped. If null, then all commands will be dumped. 300 */ dumpCommandsXml(PrintWriter printWriter, String regex)301 public void dumpCommandsXml(PrintWriter printWriter, String regex); 302 303 /** 304 * Output detailed debug info on state of command execution queue. 305 * 306 * @param printWriter 307 */ displayCommandQueue(PrintWriter printWriter)308 public void displayCommandQueue(PrintWriter printWriter); 309 310 /** 311 * Get the appropriate {@link CommandFileWatcher} for this scheduler 312 */ getCommandFileWatcher()313 public CommandFileWatcher getCommandFileWatcher(); 314 315 /** 316 * Return true if we need to shutdown the scheduler on a command errors 317 */ shouldShutdownOnCmdfileError()318 public boolean shouldShutdownOnCmdfileError(); 319 320 /** 321 * Return the error code of the last invocation that ran. 322 * Return 0 (no error), if no invocation has ran yet. 323 */ getLastInvocationExitCode()324 public ExitCode getLastInvocationExitCode(); 325 326 /** 327 * Return the {@link Throwable} from the last invocation that ran. 328 * Return null, if no throwable is available. 329 */ getLastInvocationThrowable()330 public Throwable getLastInvocationThrowable(); 331 332 /** Returns the number of Commands in ready state in the queue. */ getReadyCommandCount()333 public int getReadyCommandCount(); 334 335 /** Returns the number of Commands in executing state. */ getExecutingCommandCount()336 public int getExecutingCommandCount(); 337 338 /** Set the client to report harness data */ setClearcutClient(ClearcutClient client)339 public void setClearcutClient(ClearcutClient client); 340 341 /** Returns true if the device is used by an active invocation thread. */ isDeviceInInvocationThread(ITestDevice device)342 public boolean isDeviceInInvocationThread(ITestDevice device); 343 } 344