blob: fa394cd5079da83a606781fe8b3b5589edb83ac2 [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
Brett Chabot74541712012-08-31 18:39:00 -0700134 def Install(self, apk_path):
135 """Installs apk on device.
136
137 Args:
138 apk_path: file path to apk file on host
139
140 Returns:
141 output of install command
142 """
143 return self.SendCommand("install -r %s" % apk_path)
144
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800145 def DoesFileExist(self, src):
146 """Checks if the given path exists on device target.
147
148 Args:
149 src: file path to be checked.
150
151 Returns:
152 True if file exists
153 """
154
155 output = self.SendShellCommand("ls %s" % src)
156 error = "No such file or directory"
157
158 if error in output:
159 return False
160 return True
161
Brett Chabotccae47d2010-06-14 15:19:25 -0700162 def EnableAdbRoot(self):
163 """Enable adb root on device."""
164 output = self.SendCommand("root")
165 if "adbd is already running as root" in output:
166 return True
167 elif "restarting adbd as root" in output:
168 # device will disappear from adb, wait for it to come back
Brett Chabotcdfaae12011-06-07 10:10:38 -0700169 time.sleep(2)
Brett Chabotccae47d2010-06-14 15:19:25 -0700170 self.SendCommand("wait-for-device")
171 return True
172 else:
173 logger.Log("Unrecognized output from adb root: %s" % output)
174 return False
175
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800176 def StartInstrumentationForPackage(
177 self, package_name, runner_name, timeout_time=60*10,
178 no_window_animation=False, instrumentation_args={}):
179 """Run instrumentation test for given package and runner.
180
181 Equivalent to StartInstrumentation, except instrumentation path is
182 separated into its package and runner components.
183 """
184 instrumentation_path = "%s/%s" % (package_name, runner_name)
Brett Chabotae68f1a2009-05-28 18:29:24 -0700185 return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_time,
186 no_window_animation=no_window_animation,
187 instrumentation_args=instrumentation_args)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800188
189 def StartInstrumentation(
190 self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
191 profile=False, instrumentation_args={}):
192
193 """Runs an instrumentation class on the target.
194
195 Returns a dictionary containing the key value pairs from the
196 instrumentations result bundle and a list of TestResults. Also handles the
197 interpreting of error output from the device and raises the necessary
198 exceptions.
199
200 Args:
201 instrumentation_path: string. It should be the fully classified package
202 name, and instrumentation test runner, separated by "/"
203 e.g. com.android.globaltimelaunch/.GlobalTimeLaunch
204 timeout_time: Timeout value for the am command.
205 no_window_animation: boolean, Whether you want window animations enabled
206 or disabled
207 profile: If True, profiling will be turned on for the instrumentation.
208 instrumentation_args: Dictionary of key value bundle arguments to pass to
209 instrumentation.
210
211 Returns:
212 (test_results, inst_finished_bundle)
213
214 test_results: a list of TestResults
215 inst_finished_bundle (dict): Key/value pairs contained in the bundle that
216 is passed into ActivityManager.finishInstrumentation(). Included in this
217 bundle is the return code of the Instrumentation process, any error
218 codes reported by the activity manager, and any results explicitly added
219 by the instrumentation code.
220
221 Raises:
222 WaitForResponseTimedOutError: if timeout occurred while waiting for
223 response to adb instrument command
224 DeviceUnresponsiveError: if device system process is not responding
225 InstrumentationError: if instrumentation failed to run
226 """
227
228 command_string = self._BuildInstrumentationCommandPath(
229 instrumentation_path, no_window_animation=no_window_animation,
230 profile=profile, raw_mode=True,
231 instrumentation_args=instrumentation_args)
Brett Chabotae68f1a2009-05-28 18:29:24 -0700232 logger.Log(command_string)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800233 (test_results, inst_finished_bundle) = (
234 am_instrument_parser.ParseAmInstrumentOutput(
235 self.SendShellCommand(command_string, timeout_time=timeout_time,
236 retry_count=2)))
237
238 if "code" not in inst_finished_bundle:
239 raise errors.InstrumentationError("no test results... device setup "
240 "correctly?")
241
242 if inst_finished_bundle["code"] == "0":
243 short_msg_result = "no error message"
244 if "shortMsg" in inst_finished_bundle:
245 short_msg_result = inst_finished_bundle["shortMsg"]
Brett Chabotae68f1a2009-05-28 18:29:24 -0700246 logger.Log("Error! Test run failed: %s" % short_msg_result)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800247 raise errors.InstrumentationError(short_msg_result)
248
249 if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
250 logger.Log("INSTRUMENTATION ABORTED!")
251 raise errors.DeviceUnresponsiveError
252
253 return (test_results, inst_finished_bundle)
254
255 def StartInstrumentationNoResults(
256 self, package_name, runner_name, no_window_animation=False,
257 raw_mode=False, instrumentation_args={}):
258 """Runs instrumentation and dumps output to stdout.
259
260 Equivalent to StartInstrumentation, but will dump instrumentation
261 'normal' output to stdout, instead of parsing return results. Command will
262 never timeout.
263 """
264 adb_command_string = self.PreviewInstrumentationCommand(
265 package_name, runner_name, no_window_animation=no_window_animation,
266 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
267 logger.Log(adb_command_string)
268 run_command.RunCommand(adb_command_string, return_output=False)
269
270 def PreviewInstrumentationCommand(
271 self, package_name, runner_name, no_window_animation=False,
272 raw_mode=False, instrumentation_args={}):
273 """Returns a string of adb command that will be executed."""
274 inst_command_string = self._BuildInstrumentationCommand(
275 package_name, runner_name, no_window_animation=no_window_animation,
276 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
Brett Chabotbb5918e2011-06-17 17:07:12 -0700277 return self.PreviewShellCommand(inst_command_string)
278
279 def PreviewShellCommand(self, cmd):
280 return "adb %s shell %s" % (self._target_arg, cmd)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800281
282 def _BuildInstrumentationCommand(
283 self, package, runner_name, no_window_animation=False, profile=False,
284 raw_mode=True, instrumentation_args={}):
285 instrumentation_path = "%s/%s" % (package, runner_name)
286
287 return self._BuildInstrumentationCommandPath(
288 instrumentation_path, no_window_animation=no_window_animation,
289 profile=profile, raw_mode=raw_mode,
290 instrumentation_args=instrumentation_args)
291
292 def _BuildInstrumentationCommandPath(
293 self, instrumentation_path, no_window_animation=False, profile=False,
294 raw_mode=True, instrumentation_args={}):
295 command_string = "am instrument"
296 if no_window_animation:
297 command_string += " --no_window_animation"
298 if profile:
299 self._CreateTraceDir()
300 command_string += (
301 " -p %s/%s.dmtrace" %
302 (self.DEVICE_TRACE_DIR, instrumentation_path.split(".")[-1]))
303
304 for key, value in instrumentation_args.items():
Brett Chabote0bf8162009-06-29 13:55:30 -0700305 command_string += " -e %s '%s'" % (key, value)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800306 if raw_mode:
307 command_string += " -r"
Brett Chabot616e8f92012-10-25 11:08:14 -0700308 command_string += " -w '%s'" % instrumentation_path
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800309 return command_string
310
311 def _CreateTraceDir(self):
312 ls_response = self.SendShellCommand("ls /data/trace")
313 if ls_response.strip("#").strip(string.whitespace) != "":
314 self.SendShellCommand("create /data/trace", "mkdir /data/trace")
315 self.SendShellCommand("make /data/trace world writeable",
316 "chmod 777 /data/trace")
317
318 def WaitForDevicePm(self, wait_time=120):
319 """Waits for targeted device's package manager to be up.
320
321 Args:
322 wait_time: time in seconds to wait
323
324 Raises:
325 WaitForResponseTimedOutError if wait_time elapses and pm still does not
326 respond.
327 """
Brett Chabot72731f32009-03-31 11:14:05 -0700328 logger.Log("Waiting for device package manager...")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800329 self.SendCommand("wait-for-device")
330 # Now the device is there, but may not be running.
331 # Query the package manager with a basic command
Ot ten Thije9290dd92010-08-18 13:41:59 +0100332 try:
333 self._WaitForShellCommandContents("pm path android", "package:",
334 wait_time)
335 except errors.WaitForResponseTimedOutError:
Brett Chabot72731f32009-03-31 11:14:05 -0700336 raise errors.WaitForResponseTimedOutError(
337 "Package manager did not respond after %s seconds" % wait_time)
Brett Chabot97d5c502009-06-04 13:50:55 -0700338
Brett Chabot81c475e2012-09-11 12:57:31 -0700339 def IsInstrumentationInstalled(self, package_name, runner_name):
340 """Checks if instrumentation is present on device."""
Brett Chabot97d5c502009-06-04 13:50:55 -0700341 instrumentation_path = "%s/%s" % (package_name, runner_name)
Brett Chabot81c475e2012-09-11 12:57:31 -0700342 command = "pm list instrumentation | grep %s" % instrumentation_path
Ot ten Thije9290dd92010-08-18 13:41:59 +0100343 try:
Brett Chabot81c475e2012-09-11 12:57:31 -0700344 output = self.SendShellCommand(command)
345 return output.startswith("instrumentation:")
346 except errors.AbortError:
347 # command can return error code on failure
348 return False
Ot ten Thije9290dd92010-08-18 13:41:59 +0100349
350 def WaitForProcess(self, name, wait_time=120):
351 """Wait until a process is running on the device.
352
353 Args:
354 name: the process name as it appears in `ps`
355 wait_time: time in seconds to wait
356
357 Raises:
358 WaitForResponseTimedOutError if wait_time elapses and the process is
359 still not running
360 """
361 logger.Log("Waiting for process %s" % name)
362 self.SendCommand("wait-for-device")
363 self._WaitForShellCommandContents("ps", name, wait_time)
364
365 def WaitForProcessEnd(self, name, wait_time=120):
366 """Wait until a process is no longer running on the device.
367
368 Args:
369 name: the process name as it appears in `ps`
370 wait_time: time in seconds to wait
371
372 Raises:
373 WaitForResponseTimedOutError if wait_time elapses and the process is
374 still running
375 """
376 logger.Log("Waiting for process %s to end" % name)
377 self._WaitForShellCommandContents("ps", name, wait_time, invert=True)
378
379 def _WaitForShellCommandContents(self, command, expected, wait_time,
380 raise_abort=True, invert=False):
381 """Wait until the response to a command contains a given output.
382
383 Assumes that a only successful execution of "adb shell <command>" contains
384 the substring expected. Assumes that a device is present.
385
386 Args:
387 command: adb shell command to execute
388 expected: the string that should appear to consider the
389 command successful.
390 wait_time: time in seconds to wait
391 raise_abort: if False, retry when executing the command raises an
392 AbortError, rather than failing.
393 invert: if True, wait until the command output no longer contains the
394 expected contents.
395
396 Raises:
397 WaitForResponseTimedOutError: If wait_time elapses and the command has not
398 returned an output containing expected yet.
399 """
400 # Query the device with the command
401 success = False
402 attempts = 0
403 wait_period = 5
404 while not success and (attempts*wait_period) < wait_time:
405 # assume the command will always contain expected in the success case
406 try:
407 output = self.SendShellCommand(command, retry_count=1)
408 if ((not invert and expected in output)
409 or (invert and expected not in output)):
410 success = True
411 except errors.AbortError, e:
412 if raise_abort:
413 raise
414 # ignore otherwise
415
416 if not success:
417 time.sleep(wait_period)
418 attempts += 1
419
420 if not success:
Brett Chabot97d5c502009-06-04 13:50:55 -0700421 raise errors.WaitForResponseTimedOutError()
422
Guang Zhu863870c2010-04-15 10:48:26 -0700423 def WaitForBootComplete(self, wait_time=120):
424 """Waits for targeted device's bootcomplete flag to be set.
425
426 Args:
427 wait_time: time in seconds to wait
428
429 Raises:
430 WaitForResponseTimedOutError if wait_time elapses and pm still does not
431 respond.
432 """
433 logger.Log("Waiting for boot complete...")
434 self.SendCommand("wait-for-device")
435 # Now the device is there, but may not be running.
436 # Query the package manager with a basic command
437 boot_complete = False
438 attempts = 0
439 wait_period = 5
440 while not boot_complete and (attempts*wait_period) < wait_time:
441 output = self.SendShellCommand("getprop dev.bootcomplete", retry_count=1)
442 output = output.strip()
443 if output == "1":
444 boot_complete = True
445 else:
446 time.sleep(wait_period)
447 attempts += 1
448 if not boot_complete:
449 raise errors.WaitForResponseTimedOutError(
450 "dev.bootcomplete flag was not set after %s seconds" % wait_time)
451
452 def Sync(self, retry_count=3, runtime_restart=False):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800453 """Perform a adb sync.
Brett Chabot764d3fa2009-06-25 17:57:31 -0700454
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800455 Blocks until device package manager is responding.
Brett Chabot764d3fa2009-06-25 17:57:31 -0700456
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800457 Args:
458 retry_count: number of times to retry sync before failing
Guang Zhu863870c2010-04-15 10:48:26 -0700459 runtime_restart: stop runtime during sync and restart afterwards, useful
460 for syncing system libraries (core, framework etc)
Brett Chabot764d3fa2009-06-25 17:57:31 -0700461
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800462 Raises:
463 WaitForResponseTimedOutError if package manager does not respond
Brett Chabot8a101cb2009-05-05 12:56:39 -0700464 AbortError if unrecoverable error occurred
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800465 """
Brett Chabot8a101cb2009-05-05 12:56:39 -0700466 output = ""
467 error = None
Guang Zhu863870c2010-04-15 10:48:26 -0700468 if runtime_restart:
Brett Chabotb45644e2011-01-09 13:44:25 -0800469 self.SendShellCommand("setprop ro.test_harness 1", retry_count=retry_count)
Guang Zhu863870c2010-04-15 10:48:26 -0700470 # manual rest bootcomplete flag
471 self.SendShellCommand("setprop dev.bootcomplete 0",
472 retry_count=retry_count)
473 self.SendShellCommand("stop", retry_count=retry_count)
474
Brett Chabot8a101cb2009-05-05 12:56:39 -0700475 try:
476 output = self.SendCommand("sync", retry_count=retry_count)
477 except errors.AbortError, e:
478 error = e
479 output = e.msg
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800480 if "Read-only file system" in output:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700481 logger.SilentLog(output)
Brett Chabot72731f32009-03-31 11:14:05 -0700482 logger.Log("Remounting read-only filesystem")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800483 self.SendCommand("remount")
484 output = self.SendCommand("sync", retry_count=retry_count)
Brett Chabot8a101cb2009-05-05 12:56:39 -0700485 elif "No space left on device" in output:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700486 logger.SilentLog(output)
Brett Chabot72731f32009-03-31 11:14:05 -0700487 logger.Log("Restarting device runtime")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800488 self.SendShellCommand("stop", retry_count=retry_count)
489 output = self.SendCommand("sync", retry_count=retry_count)
490 self.SendShellCommand("start", retry_count=retry_count)
Brett Chabot8a101cb2009-05-05 12:56:39 -0700491 elif error is not None:
492 # exception occurred that cannot be recovered from
493 raise error
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800494 logger.SilentLog(output)
Guang Zhu863870c2010-04-15 10:48:26 -0700495 if runtime_restart:
496 # start runtime and wait till boot complete flag is set
497 self.SendShellCommand("start", retry_count=retry_count)
498 self.WaitForBootComplete()
499 # press the MENU key, this will disable key guard if runtime is started
500 # with ro.monkey set to 1
501 self.SendShellCommand("input keyevent 82", retry_count=retry_count)
502 else:
503 self.WaitForDevicePm()
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800504 return output
Brett Chabot72731f32009-03-31 11:14:05 -0700505
Brett Chabot764d3fa2009-06-25 17:57:31 -0700506 def GetSerialNumber(self):
507 """Returns the serial number of the targeted device."""
508 return self.SendCommand("get-serialno").strip()