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.command.CommandRunner.ExitCode;
20 import com.android.tradefed.config.ConfigurationException;
21 import com.android.tradefed.config.IConfigurationFactory;
22 import com.android.tradefed.device.FreeDeviceState;
23 import com.android.tradefed.device.ITestDevice;
24 import com.android.tradefed.device.NoDeviceException;
25 import com.android.tradefed.invoker.IInvocationContext;
26 import com.android.tradefed.invoker.ITestInvocation;
27 import com.android.tradefed.result.ITestInvocationListener;
28 
29 import java.io.PrintWriter;
30 import java.util.List;
31 import java.util.Map;
32 
33 /**
34  * A scheduler for running TradeFederation commands.
35  */
36 public interface ICommandScheduler {
37 
38     /**
39     * Listener for invocation events when invocation completes.
40     * @see #execCommand(IScheduledInvocationListener, String[])
41     */
42     public static interface IScheduledInvocationListener extends ITestInvocationListener {
43         /**
44          * Callback when an invocation is initiated. This is called before any builds are fetched.
45          *
46          * @param context
47          */
invocationInitiated(IInvocationContext context)48         public default void invocationInitiated(IInvocationContext context) {}
49 
50         /**
51          * Callback when entire invocation has completed, including all {@link
52          * ITestInvocationListener#invocationEnded(long)} events.
53          *
54          * @param context
55          * @param devicesStates
56          */
invocationComplete( IInvocationContext context, Map<ITestDevice, FreeDeviceState> devicesStates)57         public void invocationComplete(
58                 IInvocationContext context, Map<ITestDevice, FreeDeviceState> devicesStates);
59     }
60 
61     /**
62      * Adds a command to the scheduler.
63      * <p/>
64      * A command is essentially an instance of a configuration to run and its associated arguments.
65      * <p/>
66      * If "--help" argument is specified the help text for
67      * the config will be outputed to stdout. Otherwise, the config will be added to the queue to
68      * run.
69      *
70      * @param args the config arguments.
71      * @return <code>true</code> if command was added successfully
72      * @throws ConfigurationException if command could not be parsed
73      *
74      * @see IConfigurationFactory#createConfigurationFromArgs(String[])
75      */
addCommand(String[] args)76     public boolean addCommand(String[] args) throws ConfigurationException;
77 
78     /**
79      * Adds all commands from given file to the scheduler
80      *
81      * @param cmdFile the filesystem path of comand file
82      * @param extraArgs a {@link List} of {@link String} arguments to append to each command parsed
83      *            from file. Can be empty but should not be null.
84      * @throws ConfigurationException if command file could not be parsed
85      * @see CommandFileParser
86      */
addCommandFile(String cmdFile, List<String> extraArgs)87     public void addCommandFile(String cmdFile, List<String> extraArgs)
88             throws ConfigurationException;
89 
90     /**
91      * An alternate {@link #addCommand(String[])} that accepts an initial total
92      * execution time for the command.
93      * <p/>
94      * Useful when transitioning pre-existing commands from another tradefed process
95      *
96      * @param args the config arguments.
97      * @param totalExecTime the accumulated elapsed execution time of the command
98      * @return <code>true</code> if command was added successfully
99      * @throws ConfigurationException if command was invalid
100      */
addCommand(String[] args, long totalExecTime)101     public boolean addCommand(String[] args, long totalExecTime) throws ConfigurationException;
102 
103     /**
104      * Directly allocates a device and executes a command without adding it to the command queue.
105      *
106      * @param listener the {@link ICommandScheduler.IScheduledInvocationListener} to be informed
107      * @param args the command arguments
108      *
109      * @throws ConfigurationException if command was invalid
110      * @throws NoDeviceException if there is no device to use
111      */
execCommand(IScheduledInvocationListener listener, String[] args)112     public void execCommand(IScheduledInvocationListener listener, String[] args)
113             throws ConfigurationException, NoDeviceException;
114 
115     /**
116      * Directly execute command on already allocated device.
117      *
118      * @param listener the {@link ICommandScheduler.IScheduledInvocationListener} to be informed
119      * @param device the {@link ITestDevice} to use
120      * @param args the command arguments
121      *
122      * @throws ConfigurationException if command was invalid
123      */
execCommand(IScheduledInvocationListener listener, ITestDevice device, String[] args)124     public void execCommand(IScheduledInvocationListener listener, ITestDevice device,
125             String[] args) throws ConfigurationException;
126 
127     /**
128      * Directly allocates a device and executes a command without adding it to the command queue
129      * using an already existing {@link IInvocationContext}.
130      *
131      * @param context an existing {@link IInvocationContext}.
132      * @param listener the {@link ICommandScheduler.IScheduledInvocationListener} to be informed
133      * @param args the command arguments
134      * @throws ConfigurationException if command was invalid
135      * @throws NoDeviceException if there is no device to use
136      */
execCommand( IInvocationContext context, IScheduledInvocationListener listener, String[] args)137     public void execCommand(
138             IInvocationContext context, IScheduledInvocationListener listener, String[] args)
139             throws ConfigurationException, NoDeviceException;
140 
141     /**
142      * Remove all commands from scheduler
143      */
removeAllCommands()144     public void removeAllCommands();
145 
146     /**
147      * Attempt to gracefully shutdown the command scheduler.
148      * <p/>
149      * Clears commands waiting to be tested, and requests that all invocations in progress
150      * shut down gracefully.
151      * <p/>
152      * After shutdown is called, the scheduler main loop will wait for all invocations in progress
153      * to complete before exiting completely.
154      */
shutdown()155     public void shutdown();
156 
157     /**
158      * Similar to {@link #shutdown()}, but will instead wait for all commands to be executed
159      * before exiting.
160      * <p/>
161      * Note that if any commands are in loop mode, the scheduler will never exit.
162      */
shutdownOnEmpty()163     public void shutdownOnEmpty();
164 
165     /**
166      * Initiates a {@link #shutdown()} and handover to another tradefed process on this same host.
167      * <p/>
168      * The scheduler will inform the remote tradefed process listening on that port of freed devices
169      * as they become available.
170      *
171      * @return <code>true</code> if handover initiation was successful, <code>false</code>
172      * otherwise
173      */
handoverShutdown(int handoverPort)174     public boolean handoverShutdown(int handoverPort);
175 
176     /**
177      * Informs the command scheduler that initial handover exchange of devices and commands in use
178      * is complete, and it can begin scheduling operation.
179      */
handoverInitiationComplete()180     public void handoverInitiationComplete();
181 
182     /**
183      * Informs the command scheduler that a initiated handover sequence is fully complete, and it
184      * should re-initialize its remote manager on the default port.
185      */
completeHandover()186     public void completeHandover();
187 
188     /**
189      * Attempt to forcefully shutdown the command scheduler.
190      * <p/>
191      * Similar to {@link #shutdown()}, but will also forcefully kill the adb connection, in an
192      * attempt to 'inspire' invocations in progress to complete quicker.
193      */
shutdownHard()194     public void shutdownHard();
195 
196     /**
197      * Start the {@link ICommandScheduler}.
198      * <p/>
199      * Must be called before calling other methods.
200      * <p/>
201      * Will run until {@link #shutdown()} is called.
202      *
203      * see {@link Thread#start()}.
204      */
start()205     public void start();
206 
207     /**
208      * Waits for scheduler to complete.
209      *
210      * @see Thread#join()
211      */
join()212     public void join() throws InterruptedException;
213 
214     /**
215      * Waits for scheduler to complete or timeout after the duration specified in milliseconds.
216      *
217      * @see Thread#join(long)
218      */
join(long millis)219     public void join(long millis) throws InterruptedException;
220 
221     /**
222      * Waits for scheduler to start running, including waiting for handover from old TF to complete
223      * if applicable.
224      */
await()225     public void await() throws InterruptedException;
226 
227     /**
228      * Displays a list of current invocations.
229      *
230      * @param printWriter the {@link PrintWriter} to output to.
231      */
displayInvocationsInfo(PrintWriter printWriter)232     public void displayInvocationsInfo(PrintWriter printWriter);
233 
234     /**
235      * Stop a running invocation.
236      *
237      * @return true if the invocation was stopped, false otherwise
238      * @throws UnsupportedOperationException if the implementation doesn't support this
239      */
stopInvocation(ITestInvocation invocation)240     public boolean stopInvocation(ITestInvocation invocation) throws UnsupportedOperationException;
241 
242     /**
243      * Stop a running invocation by specifying it's id.
244      *
245      * @return true if the invocation was stopped, false otherwise
246      * @throws UnsupportedOperationException if the implementation doesn't support this
247      */
stopInvocation(int invocationId)248     public boolean stopInvocation(int invocationId) throws UnsupportedOperationException;
249 
250     /**
251      * Return the information on an invocation bu specifying the invocation id.
252      *
253      * @param invocationId the tracking id of the invocation.
254      * @return A {@link String} containing information about the invocation.
255      */
getInvocationInfo(int invocationId)256     public String getInvocationInfo(int invocationId);
257 
258     /**
259      * Output a list of current commands.
260      *
261      * @param printWriter the {@link PrintWriter} to output to.
262      * @param regex the regular expression to which commands should be matched in order to be
263      * printed.  If null, then all commands will be printed.
264      */
displayCommandsInfo(PrintWriter printWriter, String regex)265     public void displayCommandsInfo(PrintWriter printWriter, String regex);
266 
267     /**
268      * Dump the expanded xml file for the command with all
269      * {@link com.android.tradefed.config.Option} values specified for all current commands.
270      *
271      * @param printWriter the {@link PrintWriter} to output the status to.
272      * @param regex the regular expression to which commands should be matched in order for the
273      * xml file to be dumped.  If null, then all commands will be dumped.
274      */
dumpCommandsXml(PrintWriter printWriter, String regex)275     public void dumpCommandsXml(PrintWriter printWriter, String regex);
276 
277     /**
278      * Output detailed debug info on state of command execution queue.
279      *
280      * @param printWriter
281      */
displayCommandQueue(PrintWriter printWriter)282     public void displayCommandQueue(PrintWriter printWriter);
283 
284     /**
285      * Get the appropriate {@link CommandFileWatcher} for this scheduler
286      */
getCommandFileWatcher()287     public CommandFileWatcher getCommandFileWatcher();
288 
289     /**
290      * Return true if we need to shutdown the scheduler on a command errors
291      */
shouldShutdownOnCmdfileError()292     public boolean shouldShutdownOnCmdfileError();
293 
294     /**
295      * Return the error code of the last invocation that ran.
296      * Return 0 (no error), if no invocation has ran yet.
297      */
getLastInvocationExitCode()298     public ExitCode getLastInvocationExitCode();
299 
300     /**
301      * Return the {@link Throwable} from the last invocation that ran.
302      * Return null, if no throwable is available.
303      */
getLastInvocationThrowable()304     public Throwable getLastInvocationThrowable();
305 
306     /**
307      * Helper method, when running inside a {@link CommandRunner} context, set an exit error code
308      * and a stack trace that can be returned.
309      */
setLastInvocationExitCode(ExitCode code, Throwable stack)310     public void setLastInvocationExitCode(ExitCode code, Throwable stack);
311 
312     /** Returns the number of Commands in ready state in the queue. */
getReadyCommandCount()313     public int getReadyCommandCount();
314 }
315