blob: ad1b2c94faeb3e475c303f4947dd0ec8a0b19a41 [file] [log] [blame]
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -08001#!/usr/bin/python2.4
2#
3#
4# Copyright 2008, The Android Open Source Project
5#
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
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
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.
17
18"""Provides an interface to communicate with the device via the adb command.
19
20Assumes adb binary is currently on system path.
21"""
22# Python imports
23import os
24import string
25import time
26
27# local imports
28import am_instrument_parser
29import errors
30import logger
31import run_command
32
33
34class AdbInterface:
35 """Helper class for communicating with Android device via adb."""
36
37 # argument to pass to adb, to direct command to specific device
38 _target_arg = ""
39
40 DEVICE_TRACE_DIR = "/data/test_results/"
41
42 def SetEmulatorTarget(self):
43 """Direct all future commands to the only running emulator."""
44 self._target_arg = "-e"
45
46 def SetDeviceTarget(self):
47 """Direct all future commands to the only connected USB device."""
48 self._target_arg = "-d"
49
50 def SetTargetSerial(self, serial):
51 """Direct all future commands to Android target with the given serial."""
52 self._target_arg = "-s %s" % serial
53
54 def SendCommand(self, command_string, timeout_time=20, retry_count=3):
55 """Send a command via adb.
56
57 Args:
58 command_string: adb command to run
59 timeout_time: number of seconds to wait for command to respond before
60 retrying
61 retry_count: number of times to retry command before raising
62 WaitForResponseTimedOutError
63 Returns:
64 string output of command
65
66 Raises:
67 WaitForResponseTimedOutError if device does not respond to command
68 """
69 adb_cmd = "adb %s %s" % (self._target_arg, command_string)
70 logger.SilentLog("about to run %s" % adb_cmd)
71 return run_command.RunCommand(adb_cmd, timeout_time=timeout_time,
72 retry_count=retry_count)
73
74 def SendShellCommand(self, cmd, timeout_time=20, retry_count=3):
75 """Send a adb shell command.
76
77 Args:
78 cmd: adb shell command to run
79 timeout_time: number of seconds to wait for command to respond before
80 retrying
81 retry_count: number of times to retry command before raising
82 WaitForResponseTimedOutError
83
84 Returns:
85 string output of command
86
87 Raises:
88 WaitForResponseTimedOutError: if device does not respond to command
89 """
90 return self.SendCommand("shell %s" % cmd, timeout_time=timeout_time,
91 retry_count=retry_count)
92
93 def BugReport(self, path):
94 """Dumps adb bugreport to the file specified by the path.
95
96 Args:
97 path: Path of the file where adb bugreport is dumped to.
98 """
99 bug_output = self.SendShellCommand("bugreport", timeout_time=60)
100 bugreport_file = open(path, "w")
101 bugreport_file.write(bug_output)
102 bugreport_file.close()
103
104 def Push(self, src, dest):
105 """Pushes the file src onto the device at dest.
106
107 Args:
108 src: file path of host file to push
109 dest: destination absolute file path on device
110 """
111 self.SendCommand("push %s %s" % (src, dest), timeout_time=60)
112
113 def Pull(self, src, dest):
114 """Pulls the file src on the device onto dest on the host.
115
116 Args:
117 src: absolute file path of file on device to pull
118 dest: destination file path on host
119
120 Returns:
121 True if success and False otherwise.
122 """
123 # Create the base dir if it doesn't exist already
124 if not os.path.exists(os.path.dirname(dest)):
125 os.makedirs(os.path.dirname(dest))
126
127 if self.DoesFileExist(src):
128 self.SendCommand("pull %s %s" % (src, dest), timeout_time=60)
129 return True
130 else:
131 logger.Log("ADB Pull Failed: Source file %s does not exist." % src)
132 return False
133
134 def DoesFileExist(self, src):
135 """Checks if the given path exists on device target.
136
137 Args:
138 src: file path to be checked.
139
140 Returns:
141 True if file exists
142 """
143
144 output = self.SendShellCommand("ls %s" % src)
145 error = "No such file or directory"
146
147 if error in output:
148 return False
149 return True
150
151 def StartInstrumentationForPackage(
152 self, package_name, runner_name, timeout_time=60*10,
153 no_window_animation=False, instrumentation_args={}):
154 """Run instrumentation test for given package and runner.
155
156 Equivalent to StartInstrumentation, except instrumentation path is
157 separated into its package and runner components.
158 """
159 instrumentation_path = "%s/%s" % (package_name, runner_name)
160 return self.StartInstrumentation(self, instrumentation_path, timeout_time,
161 no_window_animation, instrumentation_args)
162
163 def StartInstrumentation(
164 self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
165 profile=False, instrumentation_args={}):
166
167 """Runs an instrumentation class on the target.
168
169 Returns a dictionary containing the key value pairs from the
170 instrumentations result bundle and a list of TestResults. Also handles the
171 interpreting of error output from the device and raises the necessary
172 exceptions.
173
174 Args:
175 instrumentation_path: string. It should be the fully classified package
176 name, and instrumentation test runner, separated by "/"
177 e.g. com.android.globaltimelaunch/.GlobalTimeLaunch
178 timeout_time: Timeout value for the am command.
179 no_window_animation: boolean, Whether you want window animations enabled
180 or disabled
181 profile: If True, profiling will be turned on for the instrumentation.
182 instrumentation_args: Dictionary of key value bundle arguments to pass to
183 instrumentation.
184
185 Returns:
186 (test_results, inst_finished_bundle)
187
188 test_results: a list of TestResults
189 inst_finished_bundle (dict): Key/value pairs contained in the bundle that
190 is passed into ActivityManager.finishInstrumentation(). Included in this
191 bundle is the return code of the Instrumentation process, any error
192 codes reported by the activity manager, and any results explicitly added
193 by the instrumentation code.
194
195 Raises:
196 WaitForResponseTimedOutError: if timeout occurred while waiting for
197 response to adb instrument command
198 DeviceUnresponsiveError: if device system process is not responding
199 InstrumentationError: if instrumentation failed to run
200 """
201
202 command_string = self._BuildInstrumentationCommandPath(
203 instrumentation_path, no_window_animation=no_window_animation,
204 profile=profile, raw_mode=True,
205 instrumentation_args=instrumentation_args)
206
207 (test_results, inst_finished_bundle) = (
208 am_instrument_parser.ParseAmInstrumentOutput(
209 self.SendShellCommand(command_string, timeout_time=timeout_time,
210 retry_count=2)))
211
212 if "code" not in inst_finished_bundle:
213 raise errors.InstrumentationError("no test results... device setup "
214 "correctly?")
215
216 if inst_finished_bundle["code"] == "0":
217 short_msg_result = "no error message"
218 if "shortMsg" in inst_finished_bundle:
219 short_msg_result = inst_finished_bundle["shortMsg"]
220 logger.Log(short_msg_result)
221 raise errors.InstrumentationError(short_msg_result)
222
223 if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
224 logger.Log("INSTRUMENTATION ABORTED!")
225 raise errors.DeviceUnresponsiveError
226
227 return (test_results, inst_finished_bundle)
228
229 def StartInstrumentationNoResults(
230 self, package_name, runner_name, no_window_animation=False,
231 raw_mode=False, instrumentation_args={}):
232 """Runs instrumentation and dumps output to stdout.
233
234 Equivalent to StartInstrumentation, but will dump instrumentation
235 'normal' output to stdout, instead of parsing return results. Command will
236 never timeout.
237 """
238 adb_command_string = self.PreviewInstrumentationCommand(
239 package_name, runner_name, no_window_animation=no_window_animation,
240 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
241 logger.Log(adb_command_string)
242 run_command.RunCommand(adb_command_string, return_output=False)
243
244 def PreviewInstrumentationCommand(
245 self, package_name, runner_name, no_window_animation=False,
246 raw_mode=False, instrumentation_args={}):
247 """Returns a string of adb command that will be executed."""
248 inst_command_string = self._BuildInstrumentationCommand(
249 package_name, runner_name, no_window_animation=no_window_animation,
250 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
251 command_string = "adb %s shell %s" % (self._target_arg, inst_command_string)
252 return command_string
253
254 def _BuildInstrumentationCommand(
255 self, package, runner_name, no_window_animation=False, profile=False,
256 raw_mode=True, instrumentation_args={}):
257 instrumentation_path = "%s/%s" % (package, runner_name)
258
259 return self._BuildInstrumentationCommandPath(
260 instrumentation_path, no_window_animation=no_window_animation,
261 profile=profile, raw_mode=raw_mode,
262 instrumentation_args=instrumentation_args)
263
264 def _BuildInstrumentationCommandPath(
265 self, instrumentation_path, no_window_animation=False, profile=False,
266 raw_mode=True, instrumentation_args={}):
267 command_string = "am instrument"
268 if no_window_animation:
269 command_string += " --no_window_animation"
270 if profile:
271 self._CreateTraceDir()
272 command_string += (
273 " -p %s/%s.dmtrace" %
274 (self.DEVICE_TRACE_DIR, instrumentation_path.split(".")[-1]))
275
276 for key, value in instrumentation_args.items():
277 command_string += " -e %s %s" % (key, value)
278 if raw_mode:
279 command_string += " -r"
280 command_string += " -w %s" % instrumentation_path
281 return command_string
282
283 def _CreateTraceDir(self):
284 ls_response = self.SendShellCommand("ls /data/trace")
285 if ls_response.strip("#").strip(string.whitespace) != "":
286 self.SendShellCommand("create /data/trace", "mkdir /data/trace")
287 self.SendShellCommand("make /data/trace world writeable",
288 "chmod 777 /data/trace")
289
290 def WaitForDevicePm(self, wait_time=120):
291 """Waits for targeted device's package manager to be up.
292
293 Args:
294 wait_time: time in seconds to wait
295
296 Raises:
297 WaitForResponseTimedOutError if wait_time elapses and pm still does not
298 respond.
299 """
Brett Chabot9bec3072009-03-31 14:21:33 -0700300 logger.Log("Waiting for device package manager...")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800301 self.SendCommand("wait-for-device")
302 # Now the device is there, but may not be running.
303 # Query the package manager with a basic command
304 pm_found = False
305 attempts = 0
306 wait_period = 5
307 while not pm_found and (attempts*wait_period) < wait_time:
308 # assume the 'adb shell pm path android' command will always
309 # return 'package: something' in the success case
310 output = self.SendShellCommand("pm path android", retry_count=1)
311 if "package:" in output:
312 pm_found = True
313 else:
314 time.sleep(wait_period)
315 attempts += 1
316 if not pm_found:
Brett Chabot9bec3072009-03-31 14:21:33 -0700317 raise errors.WaitForResponseTimedOutError(
318 "Package manager did not respond after %s seconds" % wait_time)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800319
320 def Sync(self, retry_count=3):
321 """Perform a adb sync.
322
323 Blocks until device package manager is responding.
324
325 Args:
326 retry_count: number of times to retry sync before failing
327
328 Raises:
329 WaitForResponseTimedOutError if package manager does not respond
330 """
331 output = self.SendCommand("sync", retry_count=retry_count)
332 if "Read-only file system" in output:
333 logger.SilentLog(output)
Brett Chabot9bec3072009-03-31 14:21:33 -0700334 logger.Log("Remounting read-only filesystem")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800335 self.SendCommand("remount")
336 output = self.SendCommand("sync", retry_count=retry_count)
337 if "No space left on device" in output:
338 logger.SilentLog(output)
Brett Chabot9bec3072009-03-31 14:21:33 -0700339 logger.Log("Restarting device runtime")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800340 self.SendShellCommand("stop", retry_count=retry_count)
341 output = self.SendCommand("sync", retry_count=retry_count)
342 self.SendShellCommand("start", retry_count=retry_count)
343
344 logger.SilentLog(output)
345 self.WaitForDevicePm()
346 return output
Brett Chabot9bec3072009-03-31 14:21:33 -0700347
348 def IsDevicePresent(self):
349 """Check if targeted device is present.
350
351 Returns:
352 True if device is present, False otherwise.
353 """
354 output = self.SendShellCommand("ls", retry_count=0)
355 if output.startswith("error:"):
356 return False
357 else:
358 return True