blob: ea9188c01bff3763c8c766b17d1990b576d15152 [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:
Brett Chabot8a101cb2009-05-05 12:56:39 -070067 WaitForResponseTimedOutError if device does not respond to command within time
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080068 """
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)
Brett Chabotae68f1a2009-05-28 18:29:24 -0700160 return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_time,
161 no_window_animation=no_window_animation,
162 instrumentation_args=instrumentation_args)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800163
164 def StartInstrumentation(
165 self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
166 profile=False, instrumentation_args={}):
167
168 """Runs an instrumentation class on the target.
169
170 Returns a dictionary containing the key value pairs from the
171 instrumentations result bundle and a list of TestResults. Also handles the
172 interpreting of error output from the device and raises the necessary
173 exceptions.
174
175 Args:
176 instrumentation_path: string. It should be the fully classified package
177 name, and instrumentation test runner, separated by "/"
178 e.g. com.android.globaltimelaunch/.GlobalTimeLaunch
179 timeout_time: Timeout value for the am command.
180 no_window_animation: boolean, Whether you want window animations enabled
181 or disabled
182 profile: If True, profiling will be turned on for the instrumentation.
183 instrumentation_args: Dictionary of key value bundle arguments to pass to
184 instrumentation.
185
186 Returns:
187 (test_results, inst_finished_bundle)
188
189 test_results: a list of TestResults
190 inst_finished_bundle (dict): Key/value pairs contained in the bundle that
191 is passed into ActivityManager.finishInstrumentation(). Included in this
192 bundle is the return code of the Instrumentation process, any error
193 codes reported by the activity manager, and any results explicitly added
194 by the instrumentation code.
195
196 Raises:
197 WaitForResponseTimedOutError: if timeout occurred while waiting for
198 response to adb instrument command
199 DeviceUnresponsiveError: if device system process is not responding
200 InstrumentationError: if instrumentation failed to run
201 """
202
203 command_string = self._BuildInstrumentationCommandPath(
204 instrumentation_path, no_window_animation=no_window_animation,
205 profile=profile, raw_mode=True,
206 instrumentation_args=instrumentation_args)
Brett Chabotae68f1a2009-05-28 18:29:24 -0700207 logger.Log(command_string)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800208 (test_results, inst_finished_bundle) = (
209 am_instrument_parser.ParseAmInstrumentOutput(
210 self.SendShellCommand(command_string, timeout_time=timeout_time,
211 retry_count=2)))
212
213 if "code" not in inst_finished_bundle:
214 raise errors.InstrumentationError("no test results... device setup "
215 "correctly?")
216
217 if inst_finished_bundle["code"] == "0":
218 short_msg_result = "no error message"
219 if "shortMsg" in inst_finished_bundle:
220 short_msg_result = inst_finished_bundle["shortMsg"]
Brett Chabotae68f1a2009-05-28 18:29:24 -0700221 logger.Log("Error! Test run failed: %s" % short_msg_result)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800222 raise errors.InstrumentationError(short_msg_result)
223
224 if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
225 logger.Log("INSTRUMENTATION ABORTED!")
226 raise errors.DeviceUnresponsiveError
227
228 return (test_results, inst_finished_bundle)
229
230 def StartInstrumentationNoResults(
231 self, package_name, runner_name, no_window_animation=False,
232 raw_mode=False, instrumentation_args={}):
233 """Runs instrumentation and dumps output to stdout.
234
235 Equivalent to StartInstrumentation, but will dump instrumentation
236 'normal' output to stdout, instead of parsing return results. Command will
237 never timeout.
238 """
239 adb_command_string = self.PreviewInstrumentationCommand(
240 package_name, runner_name, no_window_animation=no_window_animation,
241 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
242 logger.Log(adb_command_string)
243 run_command.RunCommand(adb_command_string, return_output=False)
244
245 def PreviewInstrumentationCommand(
246 self, package_name, runner_name, no_window_animation=False,
247 raw_mode=False, instrumentation_args={}):
248 """Returns a string of adb command that will be executed."""
249 inst_command_string = self._BuildInstrumentationCommand(
250 package_name, runner_name, no_window_animation=no_window_animation,
251 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
252 command_string = "adb %s shell %s" % (self._target_arg, inst_command_string)
253 return command_string
254
255 def _BuildInstrumentationCommand(
256 self, package, runner_name, no_window_animation=False, profile=False,
257 raw_mode=True, instrumentation_args={}):
258 instrumentation_path = "%s/%s" % (package, runner_name)
259
260 return self._BuildInstrumentationCommandPath(
261 instrumentation_path, no_window_animation=no_window_animation,
262 profile=profile, raw_mode=raw_mode,
263 instrumentation_args=instrumentation_args)
264
265 def _BuildInstrumentationCommandPath(
266 self, instrumentation_path, no_window_animation=False, profile=False,
267 raw_mode=True, instrumentation_args={}):
268 command_string = "am instrument"
269 if no_window_animation:
270 command_string += " --no_window_animation"
271 if profile:
272 self._CreateTraceDir()
273 command_string += (
274 " -p %s/%s.dmtrace" %
275 (self.DEVICE_TRACE_DIR, instrumentation_path.split(".")[-1]))
276
277 for key, value in instrumentation_args.items():
Brett Chabote0bf8162009-06-29 13:55:30 -0700278 command_string += " -e %s '%s'" % (key, value)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800279 if raw_mode:
280 command_string += " -r"
281 command_string += " -w %s" % instrumentation_path
282 return command_string
283
284 def _CreateTraceDir(self):
285 ls_response = self.SendShellCommand("ls /data/trace")
286 if ls_response.strip("#").strip(string.whitespace) != "":
287 self.SendShellCommand("create /data/trace", "mkdir /data/trace")
288 self.SendShellCommand("make /data/trace world writeable",
289 "chmod 777 /data/trace")
290
291 def WaitForDevicePm(self, wait_time=120):
292 """Waits for targeted device's package manager to be up.
293
294 Args:
295 wait_time: time in seconds to wait
296
297 Raises:
298 WaitForResponseTimedOutError if wait_time elapses and pm still does not
299 respond.
300 """
Brett Chabot72731f32009-03-31 11:14:05 -0700301 logger.Log("Waiting for device package manager...")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800302 self.SendCommand("wait-for-device")
303 # Now the device is there, but may not be running.
304 # Query the package manager with a basic command
305 pm_found = False
306 attempts = 0
307 wait_period = 5
308 while not pm_found and (attempts*wait_period) < wait_time:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700309 # assume the 'adb shell pm path android' command will always
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800310 # return 'package: something' in the success case
311 output = self.SendShellCommand("pm path android", retry_count=1)
312 if "package:" in output:
313 pm_found = True
314 else:
315 time.sleep(wait_period)
316 attempts += 1
317 if not pm_found:
Brett Chabot72731f32009-03-31 11:14:05 -0700318 raise errors.WaitForResponseTimedOutError(
319 "Package manager did not respond after %s seconds" % wait_time)
Brett Chabot97d5c502009-06-04 13:50:55 -0700320
321 def WaitForInstrumentation(self, package_name, runner_name, wait_time=120):
322 """Waits for given instrumentation to be present on device
323
324 Args:
325 wait_time: time in seconds to wait
326
327 Raises:
328 WaitForResponseTimedOutError if wait_time elapses and instrumentation
329 still not present.
330 """
331 instrumentation_path = "%s/%s" % (package_name, runner_name)
332 logger.Log("Waiting for instrumentation to be present")
333 # Query the package manager
334 inst_found = False
335 attempts = 0
336 wait_period = 5
337 while not inst_found and (attempts*wait_period) < wait_time:
338 # assume the 'adb shell pm list instrumentation'
339 # return 'instrumentation: something' in the success case
340 try:
341 output = self.SendShellCommand("pm list instrumentation | grep %s"
342 % instrumentation_path, retry_count=1)
343 if "instrumentation:" in output:
344 inst_found = True
345 except errors.AbortError, e:
346 # ignore
347 pass
348 if not inst_found:
349 time.sleep(wait_period)
350 attempts += 1
351 if not inst_found:
352 logger.Log(
353 "Could not find instrumentation %s on device. Does the "
354 "instrumentation in test's AndroidManifest.xml match definition"
355 "in test_defs.xml?" % instrumentation_path)
356 raise errors.WaitForResponseTimedOutError()
357
Guang Zhu8aff3602010-04-15 10:48:26 -0700358 def WaitForBootComplete(self, wait_time=120):
359 """Waits for targeted device's bootcomplete flag to be set.
360
361 Args:
362 wait_time: time in seconds to wait
363
364 Raises:
365 WaitForResponseTimedOutError if wait_time elapses and pm still does not
366 respond.
367 """
368 logger.Log("Waiting for boot complete...")
369 self.SendCommand("wait-for-device")
370 # Now the device is there, but may not be running.
371 # Query the package manager with a basic command
372 boot_complete = False
373 attempts = 0
374 wait_period = 5
375 while not boot_complete and (attempts*wait_period) < wait_time:
376 output = self.SendShellCommand("getprop dev.bootcomplete", retry_count=1)
377 output = output.strip()
378 if output == "1":
379 boot_complete = True
380 else:
381 time.sleep(wait_period)
382 attempts += 1
383 if not boot_complete:
384 raise errors.WaitForResponseTimedOutError(
385 "dev.bootcomplete flag was not set after %s seconds" % wait_time)
386
387 def Sync(self, retry_count=3, runtime_restart=False):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800388 """Perform a adb sync.
Brett Chabot764d3fa2009-06-25 17:57:31 -0700389
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800390 Blocks until device package manager is responding.
Brett Chabot764d3fa2009-06-25 17:57:31 -0700391
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800392 Args:
393 retry_count: number of times to retry sync before failing
Guang Zhu8aff3602010-04-15 10:48:26 -0700394 runtime_restart: stop runtime during sync and restart afterwards, useful
395 for syncing system libraries (core, framework etc)
Brett Chabot764d3fa2009-06-25 17:57:31 -0700396
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800397 Raises:
398 WaitForResponseTimedOutError if package manager does not respond
Brett Chabot8a101cb2009-05-05 12:56:39 -0700399 AbortError if unrecoverable error occurred
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800400 """
Brett Chabot8a101cb2009-05-05 12:56:39 -0700401 output = ""
402 error = None
Guang Zhu8aff3602010-04-15 10:48:26 -0700403 if runtime_restart:
404 self.SendShellCommand("setprop ro.monkey 1", retry_count=retry_count)
405 # manual rest bootcomplete flag
406 self.SendShellCommand("setprop dev.bootcomplete 0",
407 retry_count=retry_count)
408 self.SendShellCommand("stop", retry_count=retry_count)
409
Brett Chabot8a101cb2009-05-05 12:56:39 -0700410 try:
411 output = self.SendCommand("sync", retry_count=retry_count)
412 except errors.AbortError, e:
413 error = e
414 output = e.msg
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800415 if "Read-only file system" in output:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700416 logger.SilentLog(output)
Brett Chabot72731f32009-03-31 11:14:05 -0700417 logger.Log("Remounting read-only filesystem")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800418 self.SendCommand("remount")
419 output = self.SendCommand("sync", retry_count=retry_count)
Brett Chabot8a101cb2009-05-05 12:56:39 -0700420 elif "No space left on device" in output:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700421 logger.SilentLog(output)
Brett Chabot72731f32009-03-31 11:14:05 -0700422 logger.Log("Restarting device runtime")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800423 self.SendShellCommand("stop", retry_count=retry_count)
424 output = self.SendCommand("sync", retry_count=retry_count)
425 self.SendShellCommand("start", retry_count=retry_count)
Brett Chabot8a101cb2009-05-05 12:56:39 -0700426 elif error is not None:
427 # exception occurred that cannot be recovered from
428 raise error
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800429 logger.SilentLog(output)
Guang Zhu8aff3602010-04-15 10:48:26 -0700430 if runtime_restart:
431 # start runtime and wait till boot complete flag is set
432 self.SendShellCommand("start", retry_count=retry_count)
433 self.WaitForBootComplete()
434 # press the MENU key, this will disable key guard if runtime is started
435 # with ro.monkey set to 1
436 self.SendShellCommand("input keyevent 82", retry_count=retry_count)
437 else:
438 self.WaitForDevicePm()
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800439 return output
Brett Chabot72731f32009-03-31 11:14:05 -0700440
Brett Chabot764d3fa2009-06-25 17:57:31 -0700441 def GetSerialNumber(self):
442 """Returns the serial number of the targeted device."""
443 return self.SendCommand("get-serialno").strip()