4 # Copyright 2007, The Android Open Source Project
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
29 _abort_on_error = False
31 def SetAbortOnError(abort=True):
32 """Sets behavior of RunCommand to throw AbortError if command process returns
33 a negative error code"""
34 global _abort_on_error
35 _abort_on_error = abort
37 def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True,
39 """Spawn and retry a subprocess to run the given shell command.
42 cmd: shell command to run
43 timeout_time: time in seconds to wait for command to run before aborting.
44 retry_count: number of times to retry command
45 return_output: if True return output of command as string. Otherwise,
46 direct output of command to stdout.
47 stdin_input: data to feed to stdin
54 result = RunOnce(cmd, timeout_time=timeout_time,
55 return_output=return_output, stdin_input=stdin_input)
56 except errors.WaitForResponseTimedOutError:
60 logger.Log("No response for %s, retrying" % cmd)
65 def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None):
66 """Spawns a subprocess to run the given shell command.
69 cmd: shell command to run
70 timeout_time: time in seconds to wait for command to run before aborting.
71 return_output: if True return output of command as string. Otherwise,
72 direct output of command to stdout.
73 stdin_input: data to feed to stdin
77 errors.WaitForResponseTimedOutError if command did not complete within
79 errors.AbortError is command returned error code and SetAbortOnError is on.
81 start_time = time.time()
84 global _abort_on_error, error_occurred
85 error_occurred = False
90 output_dest = subprocess.PIPE
92 # None means direct to stdout
95 stdin_dest = subprocess.PIPE
98 pipe = subprocess.Popen(
100 executable='/bin/bash',
103 stderr=subprocess.STDOUT,
107 output = pipe.communicate(input=stdin_input)[0]
108 if output is not None and len(output) > 0:
111 logger.SilentLog("failed to retrieve stdout from: %s" % cmd)
114 error_occurred = True
116 logger.SilentLog("Error: %s returned %d error code" %(cmd,
118 error_occurred = True
120 t = threading.Thread(target=Run)
124 while not break_loop:
129 if (not break_loop and timeout_time is not None
130 and time.time() > start_time + timeout_time):
132 os.kill(pid[0], signal.SIGKILL)
134 # process already dead. No action required.
137 logger.SilentLog("about to raise a timeout for: %s" % cmd)
138 raise errors.WaitForResponseTimedOutError
144 if _abort_on_error and error_occurred:
145 raise errors.AbortError(msg=output)
150 def RunHostCommand(binary, valgrind=False):
151 """Run a command on the host (opt using valgrind).
153 Runs the host binary and returns the exit code.
154 If successfull, the output (stdout and stderr) are discarded,
155 but printed in case of error.
156 The command can be run under valgrind in which case all the
157 output are always discarded.
160 binary: full path of the file to be run.
161 valgrind: If True the command will be run under valgrind.
164 The command exit code (int)
167 subproc = subprocess.Popen(binary, stdout=subprocess.PIPE,
168 stderr=subprocess.STDOUT)
170 if subproc.returncode != 0: # In case of error print the output
171 print subproc.communicate()[0]
172 return subproc.returncode
174 # Need the full path to valgrind to avoid other versions on the system.
175 subproc = subprocess.Popen(["/usr/bin/valgrind", "--tool=memcheck",
176 "--leak-check=yes", "-q", binary],
177 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
178 # Cannot rely on the retcode of valgrind. Instead look for an empty output.
179 valgrind_out = subproc.communicate()[0].strip()
188 """Check that /usr/bin/valgrind exists.
190 We look for the fullpath to avoid picking up 'alternative' valgrind
194 True if a system valgrind was found.
196 return os.path.exists("/usr/bin/valgrind")