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 import com.android.tradefed.cache.ICacheClient;
21 import com.android.tradefed.result.error.ErrorIdentifier;
22 
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import java.lang.ProcessBuilder.Redirect;
27 import java.util.List;
28 
29 /**
30  * Interface for running timed operations and system commands.
31  */
32 public interface IRunUtil {
33 
34     /**
35      * An interface for asynchronously executing an operation that returns a boolean status.
36      */
37     public static interface IRunnableResult {
38         /**
39          * Execute the operation.
40          *
41          * @return <code>true</code> if operation is performed successfully, <code>false</code>
42          *         otherwise
43          * @throws Exception if operation terminated abnormally
44          */
run()45         public boolean run() throws Exception;
46 
47         /**
48          * Cancel the operation.
49          */
cancel()50         public void cancel();
51 
52         /** Returns the command associated with the runnable. */
getCommand()53         public default List<String> getCommand() {
54             return null;
55         }
56 
57         /** Returns the {@link CommandResult} associated with the command. */
getResult()58         public default CommandResult getResult() {
59             return null;
60         }
61 
62         /**
63          * Checks if the currently running operation has made progress since the last check.
64          *
65          * @param idleOutputTimeout ms idle with no observed progress before beginning to assume no
66          *     progress is being made.
67          * @return true if progress has been detected otherwise false.
68          */
checkOutputMonitor(Long idleOutputTimeout)69         public default boolean checkOutputMonitor(Long idleOutputTimeout) {
70             // Allow existing implementations not to implement this method.
71             throw new UnsupportedOperationException("checkOutputMonitor() has no implementation.");
72         }
73     }
74 
75     /**
76      * Sets the working directory for system commands.
77      *
78      * @param dir the working directory
79      *
80      * @see ProcessBuilder#directory(File)
81      */
setWorkingDir(File dir)82     public void setWorkingDir(File dir);
83 
84     /**
85      * Sets a environment variable to be used when running system commands.
86      *
87      * @param key the variable name
88      * @param value the variable value
89      *
90      * @see ProcessBuilder#environment()
91      *
92      */
setEnvVariable(String key, String value)93     public void setEnvVariable(String key, String value);
94 
95     /**
96      * Unsets an environment variable, so the system commands run without this environment variable.
97      *
98      * @param key the variable name
99      *
100      * @see ProcessBuilder#environment()
101      */
unsetEnvVariable(String key)102     public void unsetEnvVariable(String key);
103 
104     /**
105      * Set the standard error stream to redirect to the standard output stream when running system
106      * commands. Initial value is false.
107      *
108      * @param redirect new value for whether or not to redirect
109      * @see ProcessBuilder#redirectErrorStream(boolean)
110      */
setRedirectStderrToStdout(boolean redirect)111     public void setRedirectStderrToStdout(boolean redirect);
112 
113     /**
114      * Helper method to execute a system command, and aborting if it takes longer than a specified
115      * time.
116      *
117      * @param timeout maximum time to wait in ms. 0 means no timeout.
118      * @param command the specified system command and optionally arguments to exec
119      * @return a {@link CommandResult} containing result from command run
120      */
runTimedCmd(final long timeout, final String... command)121     public CommandResult runTimedCmd(final long timeout, final String... command);
122 
123     /**
124      * Helper method to execute a system command, and aborting if it takes longer than a specified
125      * time. Also monitors the output streams for activity, aborting if no stream activity is
126      * observed for a specified time. If the idleOutputTimeout is set to zero, no stream monitoring
127      * will occur.
128      *
129      * @param timeout maximum time to wait in ms. 0 means no timeout.
130      * @param idleOutputTimeout maximum time to wait in ms for output on the output streams
131      * @param command the specified system command and optionally arguments to exec
132      * @return a {@link CommandResult} containing result from command run
133      */
runTimedCmdWithOutputMonitor( final long timeout, final long idleOutputTimeout, final String... command)134     public CommandResult runTimedCmdWithOutputMonitor(
135             final long timeout, final long idleOutputTimeout, final String... command);
136 
137     /**
138      * Helper method to execute a system command, abort if it takes longer than a specified time,
139      * and redirect output to files if specified. When {@link OutputStream} are provided this way,
140      * they will be left open at the end of the function.
141      *
142      * @param timeout timeout maximum time to wait in ms. 0 means no timeout.
143      * @param idleOutputTimeout maximum time to wait in ms for output on the output streams
144      * @param stdout {@link OutputStream} where the std output will be redirected. Can be null.
145      * @param stderr {@link OutputStream} where the error output will be redirected. Can be null.
146      * @param command the specified system command and optionally arguments to exec
147      * @return a {@link CommandResult} containing result from command run
148      */
runTimedCmdWithOutputMonitor( final long timeout, final long idleOutputTimeout, OutputStream stdout, OutputStream stderr, final String... command)149     public CommandResult runTimedCmdWithOutputMonitor(
150             final long timeout,
151             final long idleOutputTimeout,
152             OutputStream stdout,
153             OutputStream stderr,
154             final String... command);
155 
156     /**
157      * Helper method to execute a system command with caching.
158      *
159      * <p>If {@code cacheClient} is specified, the caching will be enabled. If the cache is
160      * available, the cached result will be returned. Otherwise, {@link
161      * IRunUtil#runTimedCmdWithOutputMonitor( long, long, OutputStream, OutputStream, String...)}
162      * will be used to execute the command and the result will be uploaded for caching.
163      *
164      * @param timeout timeout maximum time to wait in ms. 0 means no timeout.
165      * @param idleOutputTimeout maximum time to wait in ms for output on the output streams.
166      * @param stdout {@link OutputStream} where the std output will be redirected. Can be null.
167      * @param stderr {@link OutputStream} where the error output will be redirected. Can be null.
168      * @param cacheClient an instance of {@link ICacheClient} used to handle caching.
169      * @param command the specified system command and optionally arguments to exec.
170      * @return a {@link CommandResult} containing result from command run.
171      */
runTimedCmdWithOutputMonitor( final long timeout, final long idleOutputTimeout, OutputStream stdout, OutputStream stderr, ICacheClient cacheClient, final String... command)172     public CommandResult runTimedCmdWithOutputMonitor(
173             final long timeout,
174             final long idleOutputTimeout,
175             OutputStream stdout,
176             OutputStream stderr,
177             ICacheClient cacheClient,
178             final String... command);
179 
180     /**
181      * Helper method to execute a system command, abort if it takes longer than a specified time,
182      * and redirect output to files if specified. When {@link OutputStream} are provided this way,
183      * they will be left open at the end of the function.
184      *
185      * @param timeout timeout maximum time to wait in ms. 0 means no timeout.
186      * @param stdout {@link OutputStream} where the std output will be redirected. Can be null.
187      * @param stderr {@link OutputStream} where the error output will be redirected. Can be null.
188      * @param command the specified system command and optionally arguments to exec
189      * @return a {@link CommandResult} containing result from command run
190      */
runTimedCmd( final long timeout, OutputStream stdout, OutputStream stderr, final String... command)191     public CommandResult runTimedCmd(
192             final long timeout, OutputStream stdout, OutputStream stderr, final String... command);
193 
194     /**
195      * Helper method to execute a system command, and aborting if it takes longer than a specified
196      * time.
197      *
198      * @param timeout maximum time to wait in ms for each attempt
199      * @param command the specified system command and optionally arguments to exec
200      * @param retryInterval time to wait between command retries
201      * @param attempts the maximum number of attempts to try
202      * @return a {@link CommandResult} containing result from command run
203      */
runTimedCmdRetry(final long timeout, long retryInterval, int attempts, final String... command)204     public CommandResult runTimedCmdRetry(final long timeout, long retryInterval,
205             int attempts, final String... command);
206 
207     /**
208      * Helper method to execute a system command, and aborting if it takes longer than a specified
209      * time. Also monitors the output streams for activity, aborting if no stream activity is
210      * observed for a specified time. If the idleOutputTimeout is set to zero, no stream monitoring
211      * will occur.
212      *
213      * @param timeout maximum time to wait in ms for each attempt
214      * @param idleOutputTimeout maximum time to wait in ms for output on the output streams
215      * @param command the specified system command and optionally arguments to exec
216      * @param retryInterval time to wait between command retries
217      * @param attempts the maximum number of attempts to try
218      * @return a {@link CommandResult} containing result from command run
219      */
runTimedCmdRetryWithOutputMonitor( final long timeout, final long idleOutputTimeout, long retryInterval, int attempts, final String... command)220     public CommandResult runTimedCmdRetryWithOutputMonitor(
221             final long timeout,
222             final long idleOutputTimeout,
223             long retryInterval,
224             int attempts,
225             final String... command);
226 
227     /**
228      * Helper method to execute a system command, and aborting if it takes longer than a specified
229      * time. Similar to {@link #runTimedCmd(long, String...)}, but does not log any errors on
230      * exception.
231      *
232      * @param timeout maximum time to wait in ms
233      * @param command the specified system command and optionally arguments to exec
234      * @return a {@link CommandResult} containing result from command run
235      */
runTimedCmdSilently(final long timeout, final String... command)236     public CommandResult runTimedCmdSilently(final long timeout, final String... command);
237 
238     /**
239      * Helper method to execute a system command, and aborting if it takes longer than a specified
240      * time. Similar to {@link #runTimedCmdRetry(long, long, int, String[])},
241      * but does not log any errors on exception.
242      *
243      * @param timeout maximum time to wait in ms
244      * @param command the specified system command and optionally arguments to exec
245      * @param retryInterval time to wait between command retries
246      * @param attempts the maximum number of attempts to try
247      * @return a {@link CommandResult} containing result from command run
248      */
runTimedCmdSilentlyRetry(final long timeout, long retryInterval, int attempts, final String... command)249     public CommandResult runTimedCmdSilentlyRetry(final long timeout, long retryInterval,
250             int attempts, final String... command);
251 
252     /**
253      * Helper method to execute a system command that requires stdin input, and aborting if it
254      * takes longer than a specified time.
255      *
256      * @param timeout maximum time to wait in ms
257      * @param input the stdin input to pass to process
258      * @param command the specified system command and optionally arguments to exec
259      * @return a {@link CommandResult} containing result from command run
260      */
runTimedCmdWithInput(long timeout, String input, String... command)261     CommandResult runTimedCmdWithInput(long timeout, String input, String... command);
262 
263     /**
264      * Helper method to execute a system command that requires stdin input, and aborting if it
265      * takes longer than a specified time.
266      *
267      * @param timeout maximum time to wait in ms
268      * @param input the stdin input to pass to process
269      * @param command {@link List} containing the system command and optionally arguments to exec
270      * @return a {@link CommandResult} containing result from command run
271      */
runTimedCmdWithInput(long timeout, String input, List<String> command)272     CommandResult runTimedCmdWithInput(long timeout, String input, List<String> command);
273 
274     /**
275      * Helper method to execute a system command, abort if it takes longer than a specified time,
276      * and redirect output to files if specified.
277      *
278      * @param timeout timeout maximum time to wait in ms. 0 means no timeout.
279      * @param input the stdin input to pass to process
280      * @param command the specified system command and optionally arguments to exec
281      * @param stdoutFile {@link File} where the std output will be redirected. Can be null.
282      * @param stderrFile {@link File} where the error output will be redirected. Can be null.
283      * @return a {@link CommandResult} containing result from command run
284      */
runTimedCmdWithInput( long timeout, String input, File stdoutFile, File stderrFile, final String... command)285     public CommandResult runTimedCmdWithInput(
286             long timeout, String input, File stdoutFile, File stderrFile, final String... command);
287 
288     /**
289      * Helper method to execute a system command that requires redirecting Stdin from a file, and
290      * aborting if it takes longer than a specified time.
291      *
292      * @param timeout maximum time to wait in ms
293      * @param inputRedirect the {@link File} to redirect as standard input using {@link
294      *     ProcessBuilder#redirectInput()}. If null, stdin won't be redirected.
295      * @param command the specified system command and optionally arguments to exec
296      * @return a {@link CommandResult} containing result from command run
297      */
runTimedCmdWithInputRedirect( long timeout, @Nullable File inputRedirect, String... command)298     CommandResult runTimedCmdWithInputRedirect(
299             long timeout, @Nullable File inputRedirect, String... command);
300 
301     /**
302      * Helper method to execute a system command asynchronously.
303      *
304      * <p>Will return immediately after launching command.
305      *
306      * @param command the specified system command and optionally arguments to exec
307      * @return the {@link Process} of the executed command
308      * @throws IOException if command failed to run
309      */
runCmdInBackground(String... command)310     public Process runCmdInBackground(String... command) throws IOException;
311 
312     /**
313      * Helper method to execute a system command asynchronously.
314      *
315      * <p>Will return immediately after launching command.
316      *
317      * @param redirect The {@link Redirect} to apply to the {@link ProcessBuilder}.
318      * @param command the specified system command and optionally arguments to exec
319      * @return the {@link Process} of the executed command
320      * @throws IOException if command failed to run
321      */
runCmdInBackground(Redirect redirect, final String... command)322     public Process runCmdInBackground(Redirect redirect, final String... command)
323             throws IOException;
324 
325     /**
326      * An alternate {@link #runCmdInBackground(String...)} method that accepts the command arguments
327      * in {@link List} form.
328      *
329      * @param command the {@link List} containing specified system command and optionally arguments
330      *            to exec
331      * @return the {@link Process} of the executed command
332      * @throws IOException if command failed to run
333      */
runCmdInBackground(List<String> command)334     public Process runCmdInBackground(List<String> command) throws IOException;
335 
336     /**
337      * An alternate {@link #runCmdInBackground(String...)} method that accepts the command arguments
338      * in {@link List} form.
339      *
340      * @param redirect The {@link Redirect} to apply to the {@link ProcessBuilder}.
341      * @param command the {@link List} containing specified system command and optionally arguments
342      *     to exec
343      * @return the {@link Process} of the executed command
344      * @throws IOException if command failed to run
345      */
runCmdInBackground(Redirect redirect, List<String> command)346     public Process runCmdInBackground(Redirect redirect, List<String> command) throws IOException;
347 
348     /**
349      * Running command with a {@link OutputStream} log the output of the command.
350      * Stdout and stderr are merged together.
351      * @param command the command to run
352      * @param output the OutputStream to save the output
353      * @return the {@link Process} running the command
354      * @throws IOException
355      */
runCmdInBackground(List<String> command, OutputStream output)356     public Process runCmdInBackground(List<String> command, OutputStream output)
357             throws IOException;
358 
359     /**
360      * Block and executes an operation, aborting if it takes longer than a specified time.
361      *
362      * @param timeout maximum time to wait in ms
363      * @param runnable {@link IRunUtil.IRunnableResult} to execute
364      * @param logErrors log errors on exception or not.
365      * @return the {@link CommandStatus} result of operation.
366      */
runTimed(long timeout, IRunUtil.IRunnableResult runnable, boolean logErrors)367     public CommandStatus runTimed(long timeout, IRunUtil.IRunnableResult runnable,
368             boolean logErrors);
369 
370     /**
371      * Block and executes an operation, aborting if it takes longer than a specified time. Also
372      * monitors the output streams for activity, aborting if no stream activity is observed for a
373      * specified time. If the idleOutputTimeout is set to zero, no stream monitoring will occur.
374      *
375      * @param timeout maximum time to wait in ms
376      * @param idleOutputTimeout maximum time to wait in ms for output on the output streams
377      * @param runnable {@link IRunUtil.IRunnableResult} to execute
378      * @param logErrors log errors on exception or not.
379      * @return the {@link CommandStatus} result of operation.
380      */
runTimedWithOutputMonitor( final long timeout, final long idleOutputTimeout, IRunUtil.IRunnableResult runnable, boolean logErrors)381     public CommandStatus runTimedWithOutputMonitor(
382             final long timeout,
383             final long idleOutputTimeout,
384             IRunUtil.IRunnableResult runnable,
385             boolean logErrors);
386 
387     /**
388      * Block and executes an operation multiple times until it is successful.
389      *
390      * @param opTimeout maximum time to wait in ms for one operation attempt
391      * @param pollInterval time to wait between command retries
392      * @param attempts the maximum number of attempts to try
393      * @param runnable {@link IRunUtil.IRunnableResult} to execute
394      * @return <code>true</code> if operation completed successfully before attempts reached.
395      */
runTimedRetry(long opTimeout, long pollInterval, int attempts, IRunUtil.IRunnableResult runnable)396     public boolean runTimedRetry(long opTimeout, long pollInterval, int attempts,
397             IRunUtil.IRunnableResult runnable);
398 
399     /**
400      * Block and executes an operation multiple times until it is successful. Also monitors the
401      * output streams for activity, aborting if no stream activity is observed for a specified time.
402      * If the idleOutputTimeout is set to zero, no stream monitoring will occur.
403      *
404      * @param opTimeout maximum time to wait in ms for one operation attempt
405      * @param idleOutputTimeout maximum time to wait in ms for output on the output streams
406      * @param pollInterval time to wait between command retries
407      * @param attempts the maximum number of attempts to try
408      * @param runnable {@link IRunUtil.IRunnableResult} to execute
409      * @return <code>true</code> if operation completed successfully before attempts reached.
410      */
runTimedRetryWithOutputMonitor( final long opTimeout, final long idleOutputTimeout, long pollInterval, int attempts, IRunUtil.IRunnableResult runnable)411     public boolean runTimedRetryWithOutputMonitor(
412             final long opTimeout,
413             final long idleOutputTimeout,
414             long pollInterval,
415             int attempts,
416             IRunUtil.IRunnableResult runnable);
417 
418     /**
419      * Block and executes an operation multiple times until it is successful.
420      *
421      * @param opTimeout maximum time to wait in ms for a single operation attempt
422      * @param pollInterval initial time to wait between operation attempts
423      * @param maxTime the total approximate maximum time to keep trying the operation
424      * @param runnable {@link IRunUtil.IRunnableResult} to execute
425      * @return <code>true</code> if operation completed successfully before maxTime expired
426      */
runFixedTimedRetry(final long opTimeout, final long pollInterval, final long maxTime, final IRunUtil.IRunnableResult runnable)427     public boolean runFixedTimedRetry(final long opTimeout, final long pollInterval,
428             final long maxTime, final IRunUtil.IRunnableResult runnable);
429 
430     /**
431      * Block and executes an operation multiple times until it is successful. Also monitors the
432      * output streams for activity, aborting if no stream activity is observed for a specified time.
433      * If the idleOutputTimeout is set to zero, no stream monitoring will occur.
434      *
435      * @param opTimeout maximum time to wait in ms for a single operation attempt
436      * @param idleOutputTimeout maximum time to wait in ms for output on the output streams
437      * @param pollInterval initial time to wait between operation attempts
438      * @param maxTime the total approximate maximum time to keep trying the operation
439      * @param runnable {@link IRunUtil.IRunnableResult} to execute
440      * @return <code>true</code> if operation completed successfully before maxTime expired
441      */
runFixedTimedRetryWithOutputMonitor( final long opTimeout, final long idleOutputTimeout, final long pollInterval, final long maxTime, final IRunUtil.IRunnableResult runnable)442     public boolean runFixedTimedRetryWithOutputMonitor(
443             final long opTimeout,
444             final long idleOutputTimeout,
445             final long pollInterval,
446             final long maxTime,
447             final IRunUtil.IRunnableResult runnable);
448 
449     /**
450      * Block and executes an operation multiple times until it is successful.
451      * <p/>
452      * Exponentially increase the wait time between operation attempts. This is intended to be used
453      * when performing an operation such as polling a server, to give it time to recover in case it
454      * is temporarily down.
455      *
456      * @param opTimeout maximum time to wait in ms for a single operation attempt
457      * @param initialPollInterval initial time to wait between operation attempts
458      * @param maxPollInterval the max time to wait between operation attempts
459      * @param maxTime the total approximate maximum time to keep trying the operation
460      * @param runnable {@link IRunUtil.IRunnableResult} to execute
461      * @return <code>true</code> if operation completed successfully before maxTime expired
462      */
runEscalatingTimedRetry(final long opTimeout, final long initialPollInterval, final long maxPollInterval, final long maxTime, final IRunUtil.IRunnableResult runnable)463     public boolean runEscalatingTimedRetry(final long opTimeout, final long initialPollInterval,
464             final long maxPollInterval, final long maxTime, final IRunUtil.IRunnableResult
465             runnable);
466 
467     /**
468      * Helper method to sleep for given time, ignoring any exceptions.
469      *
470      * @param time ms to sleep. values less than or equal to 0 will be ignored
471      */
sleep(long time)472     public void sleep(long time);
473 
474     /**
475      * Allows/disallows run interrupts on the current thread. If it is allowed, run operations of
476      * the current thread can be interrupted from other threads via {@link #interrupt} method.
477      *
478      * @param allow whether to allow run interrupts on the current thread.
479      */
allowInterrupt(boolean allow)480     public void allowInterrupt(boolean allow);
481 
482     /**
483      * Give the interrupt status of the RunUtil.
484      * @return true if the Run can be interrupted, false otherwise.
485      */
isInterruptAllowed()486     public boolean isInterruptAllowed();
487 
488     /**
489      * Set as interruptible after some waiting time.
490      * {@link CommandScheduler#shutdownHard()} to enforce we terminate eventually.
491      *
492      * @param thread the thread that will become interruptible.
493      * @param timeMs time to wait before setting interruptible.
494      */
setInterruptibleInFuture(Thread thread, long timeMs)495     public void setInterruptibleInFuture(Thread thread, long timeMs);
496 
497     /**
498      * Interrupts the ongoing/forthcoming run operations on the given thread. The run operations on
499      * the given thread will throw {@link RunInterruptedException}.
500      *
501      * @param thread
502      * @param message the message for {@link RunInterruptedException}.
503      */
interrupt(Thread thread, String message)504     public void interrupt(Thread thread, String message);
505 
506     /**
507      * Interrupts the ongoing/forthcoming run operations on the given thread. The run operations on
508      * the given thread will throw {@link RunInterruptedException}.
509      *
510      * @param thread
511      * @param message the message for {@link RunInterruptedException}.
512      * @param errorId Representing the cause of the interruption when known.
513      */
interrupt(Thread thread, String message, ErrorIdentifier errorId)514     public void interrupt(Thread thread, String message, ErrorIdentifier errorId);
515 
516     /**
517      * Decide whether or not when creating a process, unsetting environment variable is higher
518      * priority than setting them.
519      * By Default, unsetting is higher priority: meaning if an attempt to set a variable with the
520      * same name is made, it won't happen since the variable will be unset.
521      * Cannot be used on the default {@link IRunUtil} instance.
522      */
setEnvVariablePriority(EnvPriority priority)523     public void setEnvVariablePriority(EnvPriority priority);
524 
525     /**
526      * Allow to use linux 'kill' interruption on process running through #runTimed methods when it
527      * reaches a timeout.
528      *
529      * Cannot be used on the default {@link IRunUtil} instance.
530      */
setLinuxInterruptProcess(boolean interrupt)531     public void setLinuxInterruptProcess(boolean interrupt);
532 
533     /**
534      * Enum that defines whether setting or unsetting a particular env. variable has priority.
535      */
536     public enum EnvPriority {
537         SET,
538         UNSET
539     }
540 }
541