blob: a98a943a2bd875ef63bc9e3641a0727104188281 [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 = []
Brett Chabot8a101cb2009-05-05 12:56:39 -070061 global _abort_on_error, error_occurred
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080062 error_occurred = False
Nicolas Catania97b24c42009-04-22 11:08:32 -070063
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080064 def Run():
Brett Chabot8a101cb2009-05-05 12:56:39 -070065 global error_occurred
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080066 if return_output:
67 output_dest = subprocess.PIPE
68 else:
69 # None means direct to stdout
Nicolas Catania97b24c42009-04-22 11:08:32 -070070 output_dest = None
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080071 pipe = subprocess.Popen(
72 cmd,
73 executable='/bin/bash',
74 stdout=output_dest,
75 stderr=subprocess.STDOUT,
76 shell=True)
77 pid.append(pipe.pid)
78 try:
79 output = pipe.communicate()[0]
80 if output is not None and len(output) > 0:
81 so.append(output)
82 except OSError, e:
83 logger.SilentLog("failed to retrieve stdout from: %s" % cmd)
84 logger.Log(e)
85 so.append("ERROR")
86 error_occurred = True
Brett Chabot8a101cb2009-05-05 12:56:39 -070087 if pipe.returncode != 0:
88 logger.SilentLog("Error: %s returned %d error code" %(cmd,
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080089 pipe.returncode))
Nicolas Catania97b24c42009-04-22 11:08:32 -070090 error_occurred = True
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080091
92 t = threading.Thread(target=Run)
93 t.start()
94
95 break_loop = False
96 while not break_loop:
97 if not t.isAlive():
98 break_loop = True
99
100 # Check the timeout
101 if (not break_loop and timeout_time is not None
102 and time.time() > start_time + timeout_time):
103 try:
104 os.kill(pid[0], signal.SIGKILL)
105 except OSError:
106 # process already dead. No action required.
107 pass
108
109 logger.SilentLog("about to raise a timeout for: %s" % cmd)
110 raise errors.WaitForResponseTimedOutError
111 if not break_loop:
112 time.sleep(0.1)
113
114 t.join()
Brett Chabot8a101cb2009-05-05 12:56:39 -0700115 output = "".join(so)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800116 if _abort_on_error and error_occurred:
Brett Chabot8a101cb2009-05-05 12:56:39 -0700117 raise errors.AbortError(msg=output)
Nicolas Catania97b24c42009-04-22 11:08:32 -0700118
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800119 return "".join(so)
Nicolas Catania97b24c42009-04-22 11:08:32 -0700120
121
122def RunHostCommand(binary, valgrind=False):
123 """Run a command on the host (opt using valgrind).
124
Nicolas Catania1ecf93b2009-04-30 19:27:52 -0700125 Runs the host binary and returns the exit code.
126 If successfull, the output (stdout and stderr) are discarded,
127 but printed in case of error.
128 The command can be run under valgrind in which case all the
129 output are always discarded.
Nicolas Catania97b24c42009-04-22 11:08:32 -0700130
131 Args:
132 binary: basename of the file to be run. It is expected to be under
Nicolas Cataniaff096c12009-05-01 11:55:36 -0700133 out/host/<os>-<arch>/bin.
Nicolas Catania97b24c42009-04-22 11:08:32 -0700134 valgrind: If True the command will be run under valgrind.
135
136 Returns:
137 The command exit code (int)
138 """
Nicolas Cataniaff096c12009-05-01 11:55:36 -0700139 full_path = os.path.join(android_build.GetHostBin(), binary)
Nicolas Catania97b24c42009-04-22 11:08:32 -0700140 if not valgrind:
Nicolas Catania1ecf93b2009-04-30 19:27:52 -0700141 subproc = subprocess.Popen(full_path, stdout=subprocess.PIPE,
142 stderr=subprocess.STDOUT)
143 subproc.wait()
144 if subproc.returncode != 0: # In case of error print the output
145 print subproc.communicate()[0]
146 return subproc.returncode
Nicolas Catania97b24c42009-04-22 11:08:32 -0700147 else:
Nicolas Catania1ecf93b2009-04-30 19:27:52 -0700148 subproc = subprocess.Popen(["/usr/bin/valgrind", "-q", full_path],
149 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
150 subproc.wait()
151 return subproc.returncode