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