blob: cd39480a638e3d2daa1a1a0054af2382b2ecadc7 [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
Marco Nelissen1afdaba2014-12-03 11:27:55 -080054 def SendCommand(self, command_string, timeout_time=60, retry_count=3):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080055 """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
Santos Cordon4e0ad8f2015-05-21 12:25:05 -0700134 def Install(self, apk_path, extra_flags):
Brett Chabot74541712012-08-31 18:39:00 -0700135 """Installs apk on device.
136
137 Args:
138 apk_path: file path to apk file on host
Santos Cordon4e0ad8f2015-05-21 12:25:05 -0700139 extra_flags: Additional flags to use with adb install
Brett Chabot74541712012-08-31 18:39:00 -0700140
141 Returns:
142 output of install command
143 """
Santos Cordon4e0ad8f2015-05-21 12:25:05 -0700144 return self.SendCommand("install -r %s %s" % (extra_flags, apk_path))
Brett Chabot74541712012-08-31 18:39:00 -0700145
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800146 def DoesFileExist(self, src):
147 """Checks if the given path exists on device target.
148
149 Args:
150 src: file path to be checked.
151
152 Returns:
153 True if file exists
154 """
155
156 output = self.SendShellCommand("ls %s" % src)
157 error = "No such file or directory"
158
159 if error in output:
160 return False
161 return True
162
Brett Chabotccae47d2010-06-14 15:19:25 -0700163 def EnableAdbRoot(self):
164 """Enable adb root on device."""
165 output = self.SendCommand("root")
166 if "adbd is already running as root" in output:
167 return True
168 elif "restarting adbd as root" in output:
169 # device will disappear from adb, wait for it to come back
Brett Chabotcdfaae12011-06-07 10:10:38 -0700170 time.sleep(2)
Brett Chabotccae47d2010-06-14 15:19:25 -0700171 self.SendCommand("wait-for-device")
172 return True
173 else:
174 logger.Log("Unrecognized output from adb root: %s" % output)
175 return False
176
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800177 def StartInstrumentationForPackage(
178 self, package_name, runner_name, timeout_time=60*10,
179 no_window_animation=False, instrumentation_args={}):
180 """Run instrumentation test for given package and runner.
181
182 Equivalent to StartInstrumentation, except instrumentation path is
183 separated into its package and runner components.
184 """
185 instrumentation_path = "%s/%s" % (package_name, runner_name)
Brett Chabotae68f1a2009-05-28 18:29:24 -0700186 return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_time,
187 no_window_animation=no_window_animation,
188 instrumentation_args=instrumentation_args)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800189
190 def StartInstrumentation(
191 self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
192 profile=False, instrumentation_args={}):
193
194 """Runs an instrumentation class on the target.
195
196 Returns a dictionary containing the key value pairs from the
197 instrumentations result bundle and a list of TestResults. Also handles the
198 interpreting of error output from the device and raises the necessary
199 exceptions.
200
201 Args:
202 instrumentation_path: string. It should be the fully classified package
203 name, and instrumentation test runner, separated by "/"
204 e.g. com.android.globaltimelaunch/.GlobalTimeLaunch
205 timeout_time: Timeout value for the am command.
206 no_window_animation: boolean, Whether you want window animations enabled
207 or disabled
208 profile: If True, profiling will be turned on for the instrumentation.
209 instrumentation_args: Dictionary of key value bundle arguments to pass to
210 instrumentation.
211
212 Returns:
213 (test_results, inst_finished_bundle)
214
215 test_results: a list of TestResults
216 inst_finished_bundle (dict): Key/value pairs contained in the bundle that
217 is passed into ActivityManager.finishInstrumentation(). Included in this
218 bundle is the return code of the Instrumentation process, any error
219 codes reported by the activity manager, and any results explicitly added
220 by the instrumentation code.
221
222 Raises:
223 WaitForResponseTimedOutError: if timeout occurred while waiting for
224 response to adb instrument command
225 DeviceUnresponsiveError: if device system process is not responding
226 InstrumentationError: if instrumentation failed to run
227 """
228
229 command_string = self._BuildInstrumentationCommandPath(
230 instrumentation_path, no_window_animation=no_window_animation,
231 profile=profile, raw_mode=True,
232 instrumentation_args=instrumentation_args)
Brett Chabotae68f1a2009-05-28 18:29:24 -0700233 logger.Log(command_string)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800234 (test_results, inst_finished_bundle) = (
235 am_instrument_parser.ParseAmInstrumentOutput(
236 self.SendShellCommand(command_string, timeout_time=timeout_time,
237 retry_count=2)))
238
239 if "code" not in inst_finished_bundle:
240 raise errors.InstrumentationError("no test results... device setup "
241 "correctly?")
242
243 if inst_finished_bundle["code"] == "0":
244 short_msg_result = "no error message"
245 if "shortMsg" in inst_finished_bundle:
246 short_msg_result = inst_finished_bundle["shortMsg"]
Brett Chabotae68f1a2009-05-28 18:29:24 -0700247 logger.Log("Error! Test run failed: %s" % short_msg_result)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800248 raise errors.InstrumentationError(short_msg_result)
249
250 if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
251 logger.Log("INSTRUMENTATION ABORTED!")
252 raise errors.DeviceUnresponsiveError
253
254 return (test_results, inst_finished_bundle)
255
256 def StartInstrumentationNoResults(
257 self, package_name, runner_name, no_window_animation=False,
258 raw_mode=False, instrumentation_args={}):
259 """Runs instrumentation and dumps output to stdout.
260
261 Equivalent to StartInstrumentation, but will dump instrumentation
262 'normal' output to stdout, instead of parsing return results. Command will
263 never timeout.
264 """
265 adb_command_string = self.PreviewInstrumentationCommand(
266 package_name, runner_name, no_window_animation=no_window_animation,
267 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
268 logger.Log(adb_command_string)
269 run_command.RunCommand(adb_command_string, return_output=False)
270
271 def PreviewInstrumentationCommand(
272 self, package_name, runner_name, no_window_animation=False,
273 raw_mode=False, instrumentation_args={}):
274 """Returns a string of adb command that will be executed."""
275 inst_command_string = self._BuildInstrumentationCommand(
276 package_name, runner_name, no_window_animation=no_window_animation,
277 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
Brett Chabotbb5918e2011-06-17 17:07:12 -0700278 return self.PreviewShellCommand(inst_command_string)
279
280 def PreviewShellCommand(self, cmd):
281 return "adb %s shell %s" % (self._target_arg, cmd)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800282
283 def _BuildInstrumentationCommand(
284 self, package, runner_name, no_window_animation=False, profile=False,
285 raw_mode=True, instrumentation_args={}):
286 instrumentation_path = "%s/%s" % (package, runner_name)
287
288 return self._BuildInstrumentationCommandPath(
289 instrumentation_path, no_window_animation=no_window_animation,
290 profile=profile, raw_mode=raw_mode,
291 instrumentation_args=instrumentation_args)
292
293 def _BuildInstrumentationCommandPath(
294 self, instrumentation_path, no_window_animation=False, profile=False,
295 raw_mode=True, instrumentation_args={}):
296 command_string = "am instrument"
297 if no_window_animation:
298 command_string += " --no_window_animation"
299 if profile:
300 self._CreateTraceDir()
301 command_string += (
302 " -p %s/%s.dmtrace" %
303 (self.DEVICE_TRACE_DIR, instrumentation_path.split(".")[-1]))
304
305 for key, value in instrumentation_args.items():
Brett Chabote0bf8162009-06-29 13:55:30 -0700306 command_string += " -e %s '%s'" % (key, value)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800307 if raw_mode:
308 command_string += " -r"
Brett Chabot616e8f92012-10-25 11:08:14 -0700309 command_string += " -w '%s'" % instrumentation_path
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800310 return command_string
311
312 def _CreateTraceDir(self):
313 ls_response = self.SendShellCommand("ls /data/trace")
314 if ls_response.strip("#").strip(string.whitespace) != "":
315 self.SendShellCommand("create /data/trace", "mkdir /data/trace")
316 self.SendShellCommand("make /data/trace world writeable",
317 "chmod 777 /data/trace")
318
319 def WaitForDevicePm(self, wait_time=120):
320 """Waits for targeted device's package manager to be up.
321
322 Args:
323 wait_time: time in seconds to wait
324
325 Raises:
326 WaitForResponseTimedOutError if wait_time elapses and pm still does not
327 respond.
328 """
Brett Chabot72731f32009-03-31 11:14:05 -0700329 logger.Log("Waiting for device package manager...")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800330 self.SendCommand("wait-for-device")
331 # Now the device is there, but may not be running.
332 # Query the package manager with a basic command
Ot ten Thije9290dd92010-08-18 13:41:59 +0100333 try:
334 self._WaitForShellCommandContents("pm path android", "package:",
335 wait_time)
336 except errors.WaitForResponseTimedOutError:
Brett Chabot72731f32009-03-31 11:14:05 -0700337 raise errors.WaitForResponseTimedOutError(
338 "Package manager did not respond after %s seconds" % wait_time)
Brett Chabot97d5c502009-06-04 13:50:55 -0700339
Brett Chabot81c475e2012-09-11 12:57:31 -0700340 def IsInstrumentationInstalled(self, package_name, runner_name):
341 """Checks if instrumentation is present on device."""
Brett Chabot97d5c502009-06-04 13:50:55 -0700342 instrumentation_path = "%s/%s" % (package_name, runner_name)
Brett Chabot81c475e2012-09-11 12:57:31 -0700343 command = "pm list instrumentation | grep %s" % instrumentation_path
Ot ten Thije9290dd92010-08-18 13:41:59 +0100344 try:
Brett Chabot81c475e2012-09-11 12:57:31 -0700345 output = self.SendShellCommand(command)
346 return output.startswith("instrumentation:")
347 except errors.AbortError:
348 # command can return error code on failure
349 return False
Ot ten Thije9290dd92010-08-18 13:41:59 +0100350
351 def WaitForProcess(self, name, wait_time=120):
352 """Wait until a process is running on the device.
353
354 Args:
355 name: the process name as it appears in `ps`
356 wait_time: time in seconds to wait
357
358 Raises:
359 WaitForResponseTimedOutError if wait_time elapses and the process is
360 still not running
361 """
362 logger.Log("Waiting for process %s" % name)
363 self.SendCommand("wait-for-device")
364 self._WaitForShellCommandContents("ps", name, wait_time)
365
366 def WaitForProcessEnd(self, name, wait_time=120):
367 """Wait until a process is no longer running on the device.
368
369 Args:
370 name: the process name as it appears in `ps`
371 wait_time: time in seconds to wait
372
373 Raises:
374 WaitForResponseTimedOutError if wait_time elapses and the process is
375 still running
376 """
377 logger.Log("Waiting for process %s to end" % name)
378 self._WaitForShellCommandContents("ps", name, wait_time, invert=True)
379
380 def _WaitForShellCommandContents(self, command, expected, wait_time,
381 raise_abort=True, invert=False):
382 """Wait until the response to a command contains a given output.
383
384 Assumes that a only successful execution of "adb shell <command>" contains
385 the substring expected. Assumes that a device is present.
386
387 Args:
388 command: adb shell command to execute
389 expected: the string that should appear to consider the
390 command successful.
391 wait_time: time in seconds to wait
392 raise_abort: if False, retry when executing the command raises an
393 AbortError, rather than failing.
394 invert: if True, wait until the command output no longer contains the
395 expected contents.
396
397 Raises:
398 WaitForResponseTimedOutError: If wait_time elapses and the command has not
399 returned an output containing expected yet.
400 """
401 # Query the device with the command
402 success = False
403 attempts = 0
404 wait_period = 5
405 while not success and (attempts*wait_period) < wait_time:
406 # assume the command will always contain expected in the success case
407 try:
408 output = self.SendShellCommand(command, retry_count=1)
409 if ((not invert and expected in output)
410 or (invert and expected not in output)):
411 success = True
412 except errors.AbortError, e:
413 if raise_abort:
414 raise
415 # ignore otherwise
416
417 if not success:
418 time.sleep(wait_period)
419 attempts += 1
420
421 if not success:
Brett Chabot97d5c502009-06-04 13:50:55 -0700422 raise errors.WaitForResponseTimedOutError()
423
Guang Zhu863870c2010-04-15 10:48:26 -0700424 def WaitForBootComplete(self, wait_time=120):
425 """Waits for targeted device's bootcomplete flag to be set.
426
427 Args:
428 wait_time: time in seconds to wait
429
430 Raises:
431 WaitForResponseTimedOutError if wait_time elapses and pm still does not
432 respond.
433 """
434 logger.Log("Waiting for boot complete...")
435 self.SendCommand("wait-for-device")
436 # Now the device is there, but may not be running.
437 # Query the package manager with a basic command
438 boot_complete = False
439 attempts = 0
440 wait_period = 5
441 while not boot_complete and (attempts*wait_period) < wait_time:
442 output = self.SendShellCommand("getprop dev.bootcomplete", retry_count=1)
443 output = output.strip()
444 if output == "1":
445 boot_complete = True
446 else:
447 time.sleep(wait_period)
448 attempts += 1
449 if not boot_complete:
450 raise errors.WaitForResponseTimedOutError(
451 "dev.bootcomplete flag was not set after %s seconds" % wait_time)
452
453 def Sync(self, retry_count=3, runtime_restart=False):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800454 """Perform a adb sync.
Brett Chabot764d3fa2009-06-25 17:57:31 -0700455
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800456 Blocks until device package manager is responding.
Brett Chabot764d3fa2009-06-25 17:57:31 -0700457
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800458 Args:
459 retry_count: number of times to retry sync before failing
Guang Zhu863870c2010-04-15 10:48:26 -0700460 runtime_restart: stop runtime during sync and restart afterwards, useful
461 for syncing system libraries (core, framework etc)
Brett Chabot764d3fa2009-06-25 17:57:31 -0700462
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800463 Raises:
464 WaitForResponseTimedOutError if package manager does not respond
Brett Chabot8a101cb2009-05-05 12:56:39 -0700465 AbortError if unrecoverable error occurred
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800466 """
Brett Chabot8a101cb2009-05-05 12:56:39 -0700467 output = ""
468 error = None
Guang Zhu863870c2010-04-15 10:48:26 -0700469 if runtime_restart:
Brett Chabotb45644e2011-01-09 13:44:25 -0800470 self.SendShellCommand("setprop ro.test_harness 1", retry_count=retry_count)
Guang Zhu863870c2010-04-15 10:48:26 -0700471 # manual rest bootcomplete flag
472 self.SendShellCommand("setprop dev.bootcomplete 0",
473 retry_count=retry_count)
474 self.SendShellCommand("stop", retry_count=retry_count)
475
Brett Chabot8a101cb2009-05-05 12:56:39 -0700476 try:
477 output = self.SendCommand("sync", retry_count=retry_count)
478 except errors.AbortError, e:
479 error = e
480 output = e.msg
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800481 if "Read-only file system" in output:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700482 logger.SilentLog(output)
Brett Chabot72731f32009-03-31 11:14:05 -0700483 logger.Log("Remounting read-only filesystem")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800484 self.SendCommand("remount")
485 output = self.SendCommand("sync", retry_count=retry_count)
Brett Chabot8a101cb2009-05-05 12:56:39 -0700486 elif "No space left on device" in output:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700487 logger.SilentLog(output)
Brett Chabot72731f32009-03-31 11:14:05 -0700488 logger.Log("Restarting device runtime")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800489 self.SendShellCommand("stop", retry_count=retry_count)
490 output = self.SendCommand("sync", retry_count=retry_count)
491 self.SendShellCommand("start", retry_count=retry_count)
Brett Chabot8a101cb2009-05-05 12:56:39 -0700492 elif error is not None:
493 # exception occurred that cannot be recovered from
494 raise error
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800495 logger.SilentLog(output)
Guang Zhu863870c2010-04-15 10:48:26 -0700496 if runtime_restart:
497 # start runtime and wait till boot complete flag is set
498 self.SendShellCommand("start", retry_count=retry_count)
499 self.WaitForBootComplete()
500 # press the MENU key, this will disable key guard if runtime is started
501 # with ro.monkey set to 1
502 self.SendShellCommand("input keyevent 82", retry_count=retry_count)
503 else:
504 self.WaitForDevicePm()
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800505 return output
Brett Chabot72731f32009-03-31 11:14:05 -0700506
Brett Chabot764d3fa2009-06-25 17:57:31 -0700507 def GetSerialNumber(self):
508 """Returns the serial number of the targeted device."""
509 return self.SendCommand("get-serialno").strip()
Igor Murashkina0afc8c2014-01-22 16:22:50 -0800510
511 def RuntimeReset(self, disable_keyguard=False, retry_count=3, preview_only=False):
512 """
513 Resets the Android runtime (does *not* reboot the kernel).
514
515 Blocks until the reset is complete and the package manager
516 is available.
517
518 Args:
519 disable_keyguard: if True, presses the MENU key to disable
520 key guard, after reset is finished
521 retry_count: number of times to retry reset before failing
522
523 Raises:
524 WaitForResponseTimedOutError if package manager does not respond
525 AbortError if unrecoverable error occurred
526 """
527
528 logger.Log("adb shell stop")
529 logger.Log("adb shell start")
530
531 if not preview_only:
532 self.SendShellCommand("stop", retry_count=retry_count)
533 self.SendShellCommand("start", retry_count=retry_count)
534
535 self.WaitForDevicePm()
536
537 if disable_keyguard:
538 logger.Log("input keyevent 82 ## disable keyguard")
539 if not preview_only:
540 self.SendShellCommand("input keyevent 82", retry_count=retry_count)