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.
30 _abort_on_error
= False
32 def SetAbortOnError(abort
=True):
33 """Sets behavior of RunCommand to throw AbortError if command process returns
34 a negative error code"""
35 global _abort_on_error
36 _abort_on_error
= abort
38 def RunCommand(cmd
, timeout_time
=None, retry_count
=3, return_output
=True,
40 """Spawn and retry a subprocess to run the given shell command.
43 cmd: shell command to run
44 timeout_time: time in seconds to wait for command to run before aborting.
45 retry_count: number of times to retry command
46 return_output: if True return output of command as string. Otherwise,
47 direct output of command to stdout.
48 stdin_input: data to feed to stdin
55 result
= RunOnce(cmd
, timeout_time
=timeout_time
,
56 return_output
=return_output
, stdin_input
=stdin_input
)
57 except errors
.WaitForResponseTimedOutError
:
61 logger
.Log("No response for %s, retrying" % cmd
)
66 def RunOnce(cmd
, timeout_time
=None, return_output
=True, stdin_input
=None):
67 """Spawns a subprocess to run the given shell command.
70 cmd: shell command to run
71 timeout_time: time in seconds to wait for command to run before aborting.
72 return_output: if True return output of command as string. Otherwise,
73 direct output of command to stdout.
74 stdin_input: data to feed to stdin
78 errors.WaitForResponseTimedOutError if command did not complete within
80 errors.AbortError is command returned error code and SetAbortOnError is on.
82 start_time
= time
.time()
84 global _abort_on_error
, error_occurred
85 error_occurred
= False
88 output_dest
= tempfile
.TemporaryFile(bufsize
=0)
90 # None means direct to stdout
93 stdin_dest
= subprocess
.PIPE
96 pipe
= subprocess
.Popen(
98 executable
='/bin/bash',
101 stderr
=subprocess
.STDOUT
,
102 shell
=True, close_fds
=True,
103 preexec_fn
=lambda: signal
.signal(signal
.SIGPIPE
, signal
.SIG_DFL
))
106 global error_occurred
108 pipe
.communicate(input=stdin_input
)
112 output
= output_dest
.read()
114 if output
is not None and len(output
) > 0:
117 logger
.SilentLog("failed to retrieve stdout from: %s" % cmd
)
120 error_occurred
= True
122 logger
.SilentLog("Error: %s returned %d error code" %(cmd
,
124 error_occurred
= True
126 t
= threading
.Thread(target
=Run
)
133 # Can't kill a dead process.
136 logger
.SilentLog("about to raise a timeout for: %s" % cmd
)
137 raise errors
.WaitForResponseTimedOutError
140 if _abort_on_error
and error_occurred
:
141 raise errors
.AbortError(msg
=output
)
146 def RunHostCommand(binary
, valgrind
=False):
147 """Run a command on the host (opt using valgrind).
149 Runs the host binary and returns the exit code.
150 If successfull, the output (stdout and stderr) are discarded,
151 but printed in case of error.
152 The command can be run under valgrind in which case all the
153 output are always discarded.
156 binary: full path of the file to be run.
157 valgrind: If True the command will be run under valgrind.
160 The command exit code (int)
163 subproc
= subprocess
.Popen(binary
, stdout
=subprocess
.PIPE
,
164 stderr
=subprocess
.STDOUT
)
166 if subproc
.returncode
!= 0: # In case of error print the output
167 print subproc
.communicate()[0]
168 return subproc
.returncode
170 # Need the full path to valgrind to avoid other versions on the system.
171 subproc
= subprocess
.Popen(["/usr/bin/valgrind", "--tool=memcheck",
172 "--leak-check=yes", "-q", binary
],
173 stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
174 # Cannot rely on the retcode of valgrind. Instead look for an empty output.
175 valgrind_out
= subproc
.communicate()[0].strip()
184 """Check that /usr/bin/valgrind exists.
186 We look for the fullpath to avoid picking up 'alternative' valgrind
190 True if a system valgrind was found.
192 return os
.path
.exists("/usr/bin/valgrind")