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()
83 global _abort_on_error
, error_occurred
84 error_occurred
= False
87 output_dest
= subprocess
.PIPE
89 # None means direct to stdout
92 stdin_dest
= subprocess
.PIPE
95 pipe
= subprocess
.Popen(
97 executable
='/bin/bash',
100 stderr
=subprocess
.STDOUT
,
104 global error_occurred
106 output
= pipe
.communicate(input=stdin_input
)[0]
107 if output
is not None and len(output
) > 0:
110 logger
.SilentLog("failed to retrieve stdout from: %s" % cmd
)
113 error_occurred
= True
115 logger
.SilentLog("Error: %s returned %d error code" %(cmd
,
117 error_occurred
= True
119 t
= threading
.Thread(target
=Run
)
126 # Can't kill a dead process.
129 logger
.SilentLog("about to raise a timeout for: %s" % cmd
)
130 raise errors
.WaitForResponseTimedOutError
133 if _abort_on_error
and error_occurred
:
134 raise errors
.AbortError(msg
=output
)
139 def RunHostCommand(binary
, valgrind
=False):
140 """Run a command on the host (opt using valgrind).
142 Runs the host binary and returns the exit code.
143 If successfull, the output (stdout and stderr) are discarded,
144 but printed in case of error.
145 The command can be run under valgrind in which case all the
146 output are always discarded.
149 binary: full path of the file to be run.
150 valgrind: If True the command will be run under valgrind.
153 The command exit code (int)
156 subproc
= subprocess
.Popen(binary
, stdout
=subprocess
.PIPE
,
157 stderr
=subprocess
.STDOUT
)
159 if subproc
.returncode
!= 0: # In case of error print the output
160 print subproc
.communicate()[0]
161 return subproc
.returncode
163 # Need the full path to valgrind to avoid other versions on the system.
164 subproc
= subprocess
.Popen(["/usr/bin/valgrind", "--tool=memcheck",
165 "--leak-check=yes", "-q", binary
],
166 stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
167 # Cannot rely on the retcode of valgrind. Instead look for an empty output.
168 valgrind_out
= subproc
.communicate()[0].strip()
177 """Check that /usr/bin/valgrind exists.
179 We look for the fullpath to avoid picking up 'alternative' valgrind
183 True if a system valgrind was found.
185 return os
.path
.exists("/usr/bin/valgrind")