blob: 44499457c3413eaa4b0efb59e3baca22ba0e97b2 [file] [log] [blame]
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -08001#!/usr/bin/python2.4
2#
3#
4# Copyright 2007, The Android Open Source Project
5#
Nicolas Catania97b24c42009-04-22 11:08:32 -07006# 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
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -08009#
Nicolas Catania97b24c42009-04-22 11:08:32 -070010# http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080011#
Nicolas Catania97b24c42009-04-22 11:08:32 -070012# 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
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080016# limitations under the License.
17
18# System imports
19import os
20import signal
21import subprocess
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080022import threading
Nicolas Catania97b24c42009-04-22 11:08:32 -070023import time
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080024
25# local imports
Nicolas Cataniaff096c12009-05-01 11:55:36 -070026import android_build
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080027import errors
Nicolas Catania97b24c42009-04-22 11:08:32 -070028import logger
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080029
30_abort_on_error = False
31
32def SetAbortOnError(abort=True):
Nicolas Catania97b24c42009-04-22 11:08:32 -070033 """Sets behavior of RunCommand to throw AbortError if command process returns
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080034 a negative error code"""
35 global _abort_on_error
36 _abort_on_error = abort
Nicolas Catania97b24c42009-04-22 11:08:32 -070037
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080038def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True):
39 """Spawns a subprocess to run the given shell command, and checks for
40 timeout_time. If return_output is True, the output of the command is returned
41 as a string. Otherwise, output of command directed to stdout """
42
43 result = None
44 while True:
45 try:
Nicolas Catania97b24c42009-04-22 11:08:32 -070046 result = RunOnce(cmd, timeout_time=timeout_time,
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080047 return_output=return_output)
48 except errors.WaitForResponseTimedOutError:
49 if retry_count == 0:
50 raise
51 retry_count -= 1
52 logger.Log("No response for %s, retrying" % cmd)
53 else:
54 # Success
55 return result
56
57def RunOnce(cmd, timeout_time=None, return_output=True):
58 start_time = time.time()
59 so = []
60 pid = []
61 global _abort_on_error
62 error_occurred = False
Nicolas Catania97b24c42009-04-22 11:08:32 -070063
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080064 def Run():
65 if return_output:
66 output_dest = subprocess.PIPE
67 else:
68 # None means direct to stdout
Nicolas Catania97b24c42009-04-22 11:08:32 -070069 output_dest = None
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080070 pipe = subprocess.Popen(
71 cmd,
72 executable='/bin/bash',
73 stdout=output_dest,
74 stderr=subprocess.STDOUT,
75 shell=True)
76 pid.append(pipe.pid)
77 try:
78 output = pipe.communicate()[0]
79 if output is not None and len(output) > 0:
80 so.append(output)
81 except OSError, e:
82 logger.SilentLog("failed to retrieve stdout from: %s" % cmd)
83 logger.Log(e)
84 so.append("ERROR")
85 error_occurred = True
86 if pipe.returncode < 0:
Nicolas Catania97b24c42009-04-22 11:08:32 -070087 logger.SilentLog("Error: %s was terminated by signal %d" %(cmd,
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080088 pipe.returncode))
Nicolas Catania97b24c42009-04-22 11:08:32 -070089 error_occurred = True
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080090
91 t = threading.Thread(target=Run)
92 t.start()
93
94 break_loop = False
95 while not break_loop:
96 if not t.isAlive():
97 break_loop = True
98
99 # Check the timeout
100 if (not break_loop and timeout_time is not None
101 and time.time() > start_time + timeout_time):
102 try:
103 os.kill(pid[0], signal.SIGKILL)
104 except OSError:
105 # process already dead. No action required.
106 pass
107
108 logger.SilentLog("about to raise a timeout for: %s" % cmd)
109 raise errors.WaitForResponseTimedOutError
110 if not break_loop:
111 time.sleep(0.1)
112
113 t.join()
114
115 if _abort_on_error and error_occurred:
116 raise errors.AbortError
Nicolas Catania97b24c42009-04-22 11:08:32 -0700117
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800118 return "".join(so)
Nicolas Catania97b24c42009-04-22 11:08:32 -0700119
120
121def RunHostCommand(binary, valgrind=False):
122 """Run a command on the host (opt using valgrind).
123
Nicolas Catania1ecf93b2009-04-30 19:27:52 -0700124 Runs the host binary and returns the exit code.
125 If successfull, the output (stdout and stderr) are discarded,
126 but printed in case of error.
127 The command can be run under valgrind in which case all the
128 output are always discarded.
Nicolas Catania97b24c42009-04-22 11:08:32 -0700129
130 Args:
131 binary: basename of the file to be run. It is expected to be under
Nicolas Cataniaff096c12009-05-01 11:55:36 -0700132 out/host/<os>-<arch>/bin.
Nicolas Catania97b24c42009-04-22 11:08:32 -0700133 valgrind: If True the command will be run under valgrind.
134
135 Returns:
136 The command exit code (int)
137 """
Nicolas Cataniaff096c12009-05-01 11:55:36 -0700138 full_path = os.path.join(android_build.GetHostBin(), binary)
Nicolas Catania97b24c42009-04-22 11:08:32 -0700139 if not valgrind:
Nicolas Catania1ecf93b2009-04-30 19:27:52 -0700140 subproc = subprocess.Popen(full_path, stdout=subprocess.PIPE,
141 stderr=subprocess.STDOUT)
142 subproc.wait()
143 if subproc.returncode != 0: # In case of error print the output
144 print subproc.communicate()[0]
145 return subproc.returncode
Nicolas Catania97b24c42009-04-22 11:08:32 -0700146 else:
Nicolas Catania1ecf93b2009-04-30 19:27:52 -0700147 subproc = subprocess.Popen(["/usr/bin/valgrind", "-q", full_path],
148 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
149 subproc.wait()
150 return subproc.returncode