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.util;
18 
19 import com.android.annotations.Nullable;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.lang.ProcessBuilder.Redirect;
25 import java.util.List;
26 
27 /**
28  * Interface for running timed operations and system commands.
29  */
30 public interface IRunUtil {
31 
32     /**
33      * An interface for asynchronously executing an operation that returns a boolean status.
34      */
35     public static interface IRunnableResult {
36         /**
37          * Execute the operation.
38          *
39          * @return <code>true</code> if operation is performed successfully, <code>false</code>
40          *         otherwise
41          * @throws Exception if operation terminated abnormally
42          */
run()43         public boolean run() throws Exception;
44 
45         /**
46          * Cancel the operation.
47          */
cancel()48         public void cancel();
49 
50         /** Returns the command associated with the runnable. */
getCommand()51         public default List<String> getCommand() {
52             return null;
53         }
54 
55         /** Returns the {@link CommandResult} associated with the command. */
getResult()56         public default CommandResult getResult() {
57             return null;
58         }
59     }
60 
61     /**
62      * Sets the working directory for system commands.
63      *
64      * @param dir the working directory
65      *
66      * @see ProcessBuilder#directory(File)
67      */
setWorkingDir(File dir)68     public void setWorkingDir(File dir);
69 
70     /**
71      * Sets a environment variable to be used when running system commands.
72      *
73      * @param key the variable name
74      * @param value the variable value
75      *
76      * @see ProcessBuilder#environment()
77      *
78      */
setEnvVariable(String key, String value)79     public void setEnvVariable(String key, String value);
80 
81     /**
82      * Unsets an environment variable, so the system commands run without this environment variable.
83      *
84      * @param key the variable name
85      *
86      * @see ProcessBuilder#environment()
87      */
unsetEnvVariable(String key)88     public void unsetEnvVariable(String key);
89 
90     /**
91      * Set the standard error stream to redirect to the standard output stream when running system
92      * commands. Initial value is false.
93      *
94      * @param redirect new value for whether or not to redirect
95      * @see ProcessBuilder#redirectErrorStream(boolean)
96      */
setRedirectStderrToStdout(boolean redirect)97     public void setRedirectStderrToStdout(boolean redirect);
98 
99     /**
100      * Helper method to execute a system command, and aborting if it takes longer than a specified
101      * time.
102      *
103      * @param timeout maximum time to wait in ms. 0 means no timeout.
104      * @param command the specified system command and optionally arguments to exec
105      * @return a {@link CommandResult} containing result from command run
106      */
runTimedCmd(final long timeout, final String... command)107     public CommandResult runTimedCmd(final long timeout, final String... command);
108 
109     /**
110      * Helper method to execute a system command, abort if it takes longer than a specified time,
111      * and redirect output to files if specified. When {@link OutputStream} are provided this way,
112      * they will be left open at the end of the function.
113      *
114      * @param timeout timeout maximum time to wait in ms. 0 means no timeout.
115      * @param stdout {@link OutputStream} where the std output will be redirected. Can be null.
116      * @param stderr {@link OutputStream} where the error output will be redirected. Can be null.
117      * @param command the specified system command and optionally arguments to exec
118      * @return a {@link CommandResult} containing result from command run
119      */
runTimedCmd( final long timeout, OutputStream stdout, OutputStream stderr, final String... command)120     public CommandResult runTimedCmd(
121             final long timeout, OutputStream stdout, OutputStream stderr, final String... command);
122 
123     /**
124      * Helper method to execute a system command, and aborting if it takes longer than a specified
125      * time.
126      *
127      * @param timeout maximum time to wait in ms for each attempt
128      * @param command the specified system command and optionally arguments to exec
129      * @param retryInterval time to wait between command retries
130      * @param attempts the maximum number of attempts to try
131      * @return a {@link CommandResult} containing result from command run
132      */
runTimedCmdRetry(final long timeout, long retryInterval, int attempts, final String... command)133     public CommandResult runTimedCmdRetry(final long timeout, long retryInterval,
134             int attempts, final String... command);
135 
136     /**
137      * Helper method to execute a system command, and aborting if it takes longer than a specified
138      * time. Similar to {@link #runTimedCmd(long, String...)}, but does not log any errors on
139      * exception.
140      *
141      * @param timeout maximum time to wait in ms
142      * @param command the specified system command and optionally arguments to exec
143      * @return a {@link CommandResult} containing result from command run
144      */
runTimedCmdSilently(final long timeout, final String... command)145     public CommandResult runTimedCmdSilently(final long timeout, final String... command);
146 
147     /**
148      * Helper method to execute a system command, and aborting if it takes longer than a specified
149      * time. Similar to {@link #runTimedCmdRetry(long, long, int, String[])},
150      * but does not log any errors on exception.
151      *
152      * @param timeout maximum time to wait in ms
153      * @param command the specified system command and optionally arguments to exec
154      * @param retryInterval time to wait between command retries
155      * @param attempts the maximum number of attempts to try
156      * @return a {@link CommandResult} containing result from command run
157      */
runTimedCmdSilentlyRetry(final long timeout, long retryInterval, int attempts, final String... command)158     public CommandResult runTimedCmdSilentlyRetry(final long timeout, long retryInterval,
159             int attempts, final String... command);
160 
161     /**
162      * Helper method to execute a system command that requires stdin input, and aborting if it
163      * takes longer than a specified time.
164      *
165      * @param timeout maximum time to wait in ms
166      * @param input the stdin input to pass to process
167      * @param command the specified system command and optionally arguments to exec
168      * @return a {@link CommandResult} containing result from command run
169      */
runTimedCmdWithInput(long timeout, String input, String... command)170     CommandResult runTimedCmdWithInput(long timeout, String input, String... command);
171 
172     /**
173      * Helper method to execute a system command that requires stdin input, and aborting if it
174      * takes longer than a specified time.
175      *
176      * @param timeout maximum time to wait in ms
177      * @param input the stdin input to pass to process
178      * @param command {@link List} containing the system command and optionally arguments to exec
179      * @return a {@link CommandResult} containing result from command run
180      */
runTimedCmdWithInput(long timeout, String input, List<String> command)181     CommandResult runTimedCmdWithInput(long timeout, String input, List<String> command);
182 
183     /**
184      * Helper method to execute a system command that requires redirecting Stdin from a file, and
185      * aborting if it takes longer than a specified time.
186      *
187      * @param timeout maximum time to wait in ms
188      * @param inputRedirect the {@link File} to redirect as standard input using {@link
189      *     ProcessBuilder#redirectInput()}. If null, stdin won't be redirected.
190      * @param command the specified system command and optionally arguments to exec
191      * @return a {@link CommandResult} containing result from command run
192      */
runTimedCmdWithInputRedirect( long timeout, @Nullable File inputRedirect, String... command)193     CommandResult runTimedCmdWithInputRedirect(
194             long timeout, @Nullable File inputRedirect, String... command);
195 
196     /**
197      * Helper method to execute a system command asynchronously.
198      *
199      * <p>Will return immediately after launching command.
200      *
201      * @param command the specified system command and optionally arguments to exec
202      * @return the {@link Process} of the executed command
203      * @throws IOException if command failed to run
204      */
runCmdInBackground(String... command)205     public Process runCmdInBackground(String... command) throws IOException;
206 
207     /**
208      * Helper method to execute a system command asynchronously.
209      *
210      * <p>Will return immediately after launching command.
211      *
212      * @param redirect The {@link Redirect} to apply to the {@link ProcessBuilder}.
213      * @param command the specified system command and optionally arguments to exec
214      * @return the {@link Process} of the executed command
215      * @throws IOException if command failed to run
216      */
runCmdInBackground(Redirect redirect, final String... command)217     public Process runCmdInBackground(Redirect redirect, final String... command)
218             throws IOException;
219 
220     /**
221      * An alternate {@link #runCmdInBackground(String...)} method that accepts the command arguments
222      * in {@link List} form.
223      *
224      * @param command the {@link List} containing specified system command and optionally arguments
225      *            to exec
226      * @return the {@link Process} of the executed command
227      * @throws IOException if command failed to run
228      */
runCmdInBackground(List<String> command)229     public Process runCmdInBackground(List<String> command) throws IOException;
230 
231     /**
232      * An alternate {@link #runCmdInBackground(String...)} method that accepts the command arguments
233      * in {@link List} form.
234      *
235      * @param redirect The {@link Redirect} to apply to the {@link ProcessBuilder}.
236      * @param command the {@link List} containing specified system command and optionally arguments
237      *     to exec
238      * @return the {@link Process} of the executed command
239      * @throws IOException if command failed to run
240      */
runCmdInBackground(Redirect redirect, List<String> command)241     public Process runCmdInBackground(Redirect redirect, List<String> command) throws IOException;
242 
243     /**
244      * Running command with a {@link OutputStream} log the output of the command.
245      * Stdout and stderr are merged together.
246      * @param command the command to run
247      * @param output the OutputStream to save the output
248      * @return the {@link Process} running the command
249      * @throws IOException
250      */
runCmdInBackground(List<String> command, OutputStream output)251     public Process runCmdInBackground(List<String> command, OutputStream output)
252             throws IOException;
253 
254     /**
255      * Block and executes an operation, aborting if it takes longer than a specified time.
256      *
257      * @param timeout maximum time to wait in ms
258      * @param runnable {@link IRunUtil.IRunnableResult} to execute
259      * @param logErrors log errors on exception or not.
260      * @return the {@link CommandStatus} result of operation.
261      */
runTimed(long timeout, IRunUtil.IRunnableResult runnable, boolean logErrors)262     public CommandStatus runTimed(long timeout, IRunUtil.IRunnableResult runnable,
263             boolean logErrors);
264 
265     /**
266      * Block and executes an operation multiple times until it is successful.
267      *
268      * @param opTimeout maximum time to wait in ms for one operation attempt
269      * @param pollInterval time to wait between command retries
270      * @param attempts the maximum number of attempts to try
271      * @param runnable {@link IRunUtil.IRunnableResult} to execute
272      * @return <code>true</code> if operation completed successfully before attempts reached.
273      */
runTimedRetry(long opTimeout, long pollInterval, int attempts, IRunUtil.IRunnableResult runnable)274     public boolean runTimedRetry(long opTimeout, long pollInterval, int attempts,
275             IRunUtil.IRunnableResult runnable);
276 
277     /**
278      * Block and executes an operation multiple times until it is successful.
279      *
280      * @param opTimeout maximum time to wait in ms for a single operation attempt
281      * @param pollInterval initial time to wait between operation attempts
282      * @param maxTime the total approximate maximum time to keep trying the operation
283      * @param runnable {@link IRunUtil.IRunnableResult} to execute
284      * @return <code>true</code> if operation completed successfully before maxTime expired
285      */
runFixedTimedRetry(final long opTimeout, final long pollInterval, final long maxTime, final IRunUtil.IRunnableResult runnable)286     public boolean runFixedTimedRetry(final long opTimeout, final long pollInterval,
287             final long maxTime, final IRunUtil.IRunnableResult runnable);
288 
289     /**
290      * Block and executes an operation multiple times until it is successful.
291      * <p/>
292      * Exponentially increase the wait time between operation attempts. This is intended to be used
293      * when performing an operation such as polling a server, to give it time to recover in case it
294      * is temporarily down.
295      *
296      * @param opTimeout maximum time to wait in ms for a single operation attempt
297      * @param initialPollInterval initial time to wait between operation attempts
298      * @param maxPollInterval the max time to wait between operation attempts
299      * @param maxTime the total approximate maximum time to keep trying the operation
300      * @param runnable {@link IRunUtil.IRunnableResult} to execute
301      * @return <code>true</code> if operation completed successfully before maxTime expired
302      */
runEscalatingTimedRetry(final long opTimeout, final long initialPollInterval, final long maxPollInterval, final long maxTime, final IRunUtil.IRunnableResult runnable)303     public boolean runEscalatingTimedRetry(final long opTimeout, final long initialPollInterval,
304             final long maxPollInterval, final long maxTime, final IRunUtil.IRunnableResult
305             runnable);
306 
307     /**
308      * Helper method to sleep for given time, ignoring any exceptions.
309      *
310      * @param time ms to sleep. values less than or equal to 0 will be ignored
311      */
sleep(long time)312     public void sleep(long time);
313 
314     /**
315      * Allows/disallows run interrupts on the current thread. If it is allowed, run operations of
316      * the current thread can be interrupted from other threads via {@link #interrupt} method.
317      *
318      * @param allow whether to allow run interrupts on the current thread.
319      */
allowInterrupt(boolean allow)320     public void allowInterrupt(boolean allow);
321 
322     /**
323      * Give the interrupt status of the RunUtil.
324      * @return true if the Run can be interrupted, false otherwise.
325      */
isInterruptAllowed()326     public boolean isInterruptAllowed();
327 
328     /**
329      * Set as interruptible after some waiting time.
330      * {@link CommandScheduler#shutdownHard()} to enforce we terminate eventually.
331      *
332      * @param thread the thread that will become interruptible.
333      * @param timeMs time to wait before setting interruptible.
334      */
setInterruptibleInFuture(Thread thread, long timeMs)335     public void setInterruptibleInFuture(Thread thread, long timeMs);
336 
337     /**
338      * Interrupts the ongoing/forthcoming run operations on the given thread. The run operations on
339      * the given thread will throw {@link RunInterruptedException}.
340      *
341      * @param thread
342      * @param message the message for {@link RunInterruptedException}.
343      */
interrupt(Thread thread, String message)344     public void interrupt(Thread thread, String message);
345 
346     /**
347      * Decide whether or not when creating a process, unsetting environment variable is higher
348      * priority than setting them.
349      * By Default, unsetting is higher priority: meaning if an attempt to set a variable with the
350      * same name is made, it won't happen since the variable will be unset.
351      * Cannot be used on the default {@link IRunUtil} instance.
352      */
setEnvVariablePriority(EnvPriority priority)353     public void setEnvVariablePriority(EnvPriority priority);
354 
355     /**
356      * Enum that defines whether setting or unsetting a particular env. variable has priority.
357      */
358     public enum EnvPriority {
359         SET,
360         UNSET
361     }
362 }
363