4 # Copyright 2008, The Android Open Source Project
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 """Provides an interface to communicate with the device via the adb command.
20 Assumes adb binary is currently on system path.
28 import am_instrument_parser
35 """Helper class for communicating with Android device via adb."""
37 # argument to pass to adb, to direct command to specific device
40 DEVICE_TRACE_DIR
= "/data/test_results/"
42 def SetEmulatorTarget(self
):
43 """Direct all future commands to the only running emulator."""
44 self
._target
_arg
= "-e"
46 def SetDeviceTarget(self
):
47 """Direct all future commands to the only connected USB device."""
48 self
._target
_arg
= "-d"
50 def SetTargetSerial(self
, serial
):
51 """Direct all future commands to Android target with the given serial."""
52 self
._target
_arg
= "-s %s" % serial
54 def SendCommand(self
, command_string
, timeout_time
=20, retry_count
=3):
55 """Send a command via adb.
58 command_string: adb command to run
59 timeout_time: number of seconds to wait for command to respond before
61 retry_count: number of times to retry command before raising
62 WaitForResponseTimedOutError
64 string output of command
67 WaitForResponseTimedOutError if device does not respond to command within time
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
)
74 def SendShellCommand(self
, cmd
, timeout_time
=20, retry_count
=3):
75 """Send a adb shell command.
78 cmd: adb shell command to run
79 timeout_time: number of seconds to wait for command to respond before
81 retry_count: number of times to retry command before raising
82 WaitForResponseTimedOutError
85 string output of command
88 WaitForResponseTimedOutError: if device does not respond to command
90 return self
.SendCommand("shell %s" % cmd
, timeout_time
=timeout_time
,
91 retry_count
=retry_count
)
93 def BugReport(self
, path
):
94 """Dumps adb bugreport to the file specified by the path.
97 path: Path of the file where adb bugreport is dumped to.
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()
104 def Push(self
, src
, dest
):
105 """Pushes the file src onto the device at dest.
108 src: file path of host file to push
109 dest: destination absolute file path on device
111 self
.SendCommand("push %s %s" % (src
, dest
), timeout_time
=60)
113 def Pull(self
, src
, dest
):
114 """Pulls the file src on the device onto dest on the host.
117 src: absolute file path of file on device to pull
118 dest: destination file path on host
121 True if success and False otherwise.
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
))
127 if self
.DoesFileExist(src
):
128 self
.SendCommand("pull %s %s" % (src
, dest
), timeout_time
=60)
131 logger
.Log("ADB Pull Failed: Source file %s does not exist." % src
)
134 def DoesFileExist(self
, src
):
135 """Checks if the given path exists on device target.
138 src: file path to be checked.
144 output
= self
.SendShellCommand("ls %s" % src
)
145 error
= "No such file or directory"
151 def EnableAdbRoot(self
):
152 """Enable adb root on device."""
153 output
= self
.SendCommand("root")
154 if "adbd is already running as root" in output
:
156 elif "restarting adbd as root" in output
:
157 # device will disappear from adb, wait for it to come back
158 self
.SendCommand("wait-for-device")
161 logger
.Log("Unrecognized output from adb root: %s" % output
)
164 def StartInstrumentationForPackage(
165 self
, package_name
, runner_name
, timeout_time
=60*10,
166 no_window_animation
=False, instrumentation_args
={}):
167 """Run instrumentation test for given package and runner.
169 Equivalent to StartInstrumentation, except instrumentation path is
170 separated into its package and runner components.
172 instrumentation_path
= "%s/%s" % (package_name
, runner_name
)
173 return self
.StartInstrumentation(instrumentation_path
, timeout_time
=timeout_time
,
174 no_window_animation
=no_window_animation
,
175 instrumentation_args
=instrumentation_args
)
177 def StartInstrumentation(
178 self
, instrumentation_path
, timeout_time
=60*10, no_window_animation
=False,
179 profile
=False, instrumentation_args
={}, silent_log
=False):
181 """Runs an instrumentation class on the target.
183 Returns a dictionary containing the key value pairs from the
184 instrumentations result bundle and a list of TestResults. Also handles the
185 interpreting of error output from the device and raises the necessary
189 instrumentation_path: string. It should be the fully classified package
190 name, and instrumentation test runner, separated by "/"
191 e.g. com.android.globaltimelaunch/.GlobalTimeLaunch
192 timeout_time: Timeout value for the am command.
193 no_window_animation: boolean, Whether you want window animations enabled
195 profile: If True, profiling will be turned on for the instrumentation.
196 instrumentation_args: Dictionary of key value bundle arguments to pass to
198 silent_log: If True, the invocation of the instrumentation test runner
202 (test_results, inst_finished_bundle)
204 test_results: a list of TestResults
205 inst_finished_bundle (dict): Key/value pairs contained in the bundle that
206 is passed into ActivityManager.finishInstrumentation(). Included in this
207 bundle is the return code of the Instrumentation process, any error
208 codes reported by the activity manager, and any results explicitly added
209 by the instrumentation code.
212 WaitForResponseTimedOutError: if timeout occurred while waiting for
213 response to adb instrument command
214 DeviceUnresponsiveError: if device system process is not responding
215 InstrumentationError: if instrumentation failed to run
218 command_string
= self
._BuildInstrumentationCommandPath
(
219 instrumentation_path
, no_window_animation
=no_window_animation
,
220 profile
=profile
, raw_mode
=True,
221 instrumentation_args
=instrumentation_args
)
223 logger
.SilentLog(command_string
)
225 logger
.Log(command_string
)
226 (test_results
, inst_finished_bundle
) = (
227 am_instrument_parser
.ParseAmInstrumentOutput(
228 self
.SendShellCommand(command_string
, timeout_time
=timeout_time
,
230 if "code" not in inst_finished_bundle
:
231 logger
.Log('No code available. inst_finished_bundle contains: %s '
232 % inst_finished_bundle
)
233 raise errors
.InstrumentationError("no test results... device setup "
236 if inst_finished_bundle
["code"] == "0":
237 long_msg_result
= "no error message"
238 if "longMsg" in inst_finished_bundle
:
239 long_msg_result
= inst_finished_bundle
["longMsg"]
240 logger
.Log("Error! Test run failed: %s" % long_msg_result
)
241 raise errors
.InstrumentationError(long_msg_result
)
243 if "INSTRUMENTATION_ABORTED" in inst_finished_bundle
:
244 logger
.Log("INSTRUMENTATION ABORTED!")
245 raise errors
.DeviceUnresponsiveError
247 return (test_results
, inst_finished_bundle
)
249 def StartInstrumentationNoResults(
250 self
, package_name
, runner_name
, no_window_animation
=False,
251 raw_mode
=False, instrumentation_args
={}):
252 """Runs instrumentation and dumps output to stdout.
254 Equivalent to StartInstrumentation, but will dump instrumentation
255 'normal' output to stdout, instead of parsing return results. Command will
258 adb_command_string
= self
.PreviewInstrumentationCommand(
259 package_name
, runner_name
, no_window_animation
=no_window_animation
,
260 raw_mode
=raw_mode
, instrumentation_args
=instrumentation_args
)
261 logger
.Log(adb_command_string
)
262 run_command
.RunCommand(adb_command_string
, return_output
=False)
264 def PreviewInstrumentationCommand(
265 self
, package_name
, runner_name
, no_window_animation
=False,
266 raw_mode
=False, instrumentation_args
={}):
267 """Returns a string of adb command that will be executed."""
268 inst_command_string
= self
._BuildInstrumentationCommand
(
269 package_name
, runner_name
, no_window_animation
=no_window_animation
,
270 raw_mode
=raw_mode
, instrumentation_args
=instrumentation_args
)
271 command_string
= "adb %s shell %s" % (self
._target
_arg
, inst_command_string
)
272 return command_string
274 def _BuildInstrumentationCommand(
275 self
, package
, runner_name
, no_window_animation
=False, profile
=False,
276 raw_mode
=True, instrumentation_args
={}):
277 instrumentation_path
= "%s/%s" % (package
, runner_name
)
279 return self
._BuildInstrumentationCommandPath
(
280 instrumentation_path
, no_window_animation
=no_window_animation
,
281 profile
=profile
, raw_mode
=raw_mode
,
282 instrumentation_args
=instrumentation_args
)
284 def _BuildInstrumentationCommandPath(
285 self
, instrumentation_path
, no_window_animation
=False, profile
=False,
286 raw_mode
=True, instrumentation_args
={}):
287 command_string
= "am instrument"
288 if no_window_animation
:
289 command_string
+= " --no_window_animation"
291 self
._CreateTraceDir
()
293 " -p %s/%s.dmtrace" %
294 (self
.DEVICE_TRACE_DIR
, instrumentation_path
.split(".")[-1]))
296 for key
, value
in instrumentation_args
.items():
297 command_string
+= " -e %s '%s'" % (key
, value
)
299 command_string
+= " -r"
300 command_string
+= " -w %s" % instrumentation_path
301 return command_string
303 def _CreateTraceDir(self
):
304 ls_response
= self
.SendShellCommand("ls /data/trace")
305 if ls_response
.strip("#").strip(string
.whitespace
) != "":
306 self
.SendShellCommand("create /data/trace", "mkdir /data/trace")
307 self
.SendShellCommand("make /data/trace world writeable",
308 "chmod 777 /data/trace")
310 def WaitForDevicePm(self
, wait_time
=120):
311 """Waits for targeted device's package manager to be up.
314 wait_time: time in seconds to wait
317 WaitForResponseTimedOutError if wait_time elapses and pm still does not
320 logger
.Log("Waiting for device package manager...")
321 self
.SendCommand("wait-for-device")
322 # Now the device is there, but may not be running.
323 # Query the package manager with a basic command
325 self
._WaitForShellCommandContents
("pm path android", "package:",
327 except errors
.WaitForResponseTimedOutError
:
328 raise errors
.WaitForResponseTimedOutError(
329 "Package manager did not respond after %s seconds" % wait_time
)
331 def WaitForInstrumentation(self
, package_name
, runner_name
, wait_time
=120):
332 """Waits for given instrumentation to be present on device
335 wait_time: time in seconds to wait
338 WaitForResponseTimedOutError if wait_time elapses and instrumentation
341 instrumentation_path
= "%s/%s" % (package_name
, runner_name
)
342 logger
.Log("Waiting for instrumentation to be present")
343 # Query the package manager
345 command
= "pm list instrumentation | grep %s" % instrumentation_path
346 self
._WaitForShellCommandContents
(command
, "instrumentation:", wait_time
,
348 except errors
.WaitForResponseTimedOutError
:
350 "Could not find instrumentation %s on device. Does the "
351 "instrumentation in test's AndroidManifest.xml match definition"
352 "in test_defs.xml?" % instrumentation_path
)
355 def WaitForProcess(self
, name
, wait_time
=120):
356 """Wait until a process is running on the device.
359 name: the process name as it appears in `ps`
360 wait_time: time in seconds to wait
363 WaitForResponseTimedOutError if wait_time elapses and the process is
366 logger
.Log("Waiting for process %s" % name
)
367 self
.SendCommand("wait-for-device")
368 self
._WaitForShellCommandContents
("ps", name
, wait_time
)
370 def WaitForProcessEnd(self
, name
, wait_time
=120):
371 """Wait until a process is no longer running on the device.
374 name: the process name as it appears in `ps`
375 wait_time: time in seconds to wait
378 WaitForResponseTimedOutError if wait_time elapses and the process is
381 logger
.Log("Waiting for process %s to end" % name
)
382 self
._WaitForShellCommandContents
("ps", name
, wait_time
, invert
=True)
384 def _WaitForShellCommandContents(self
, command
, expected
, wait_time
,
385 raise_abort
=True, invert
=False):
386 """Wait until the response to a command contains a given output.
388 Assumes that a only successful execution of "adb shell <command>" contains
389 the substring expected. Assumes that a device is present.
392 command: adb shell command to execute
393 expected: the string that should appear to consider the
395 wait_time: time in seconds to wait
396 raise_abort: if False, retry when executing the command raises an
397 AbortError, rather than failing.
398 invert: if True, wait until the command output no longer contains the
402 WaitForResponseTimedOutError: If wait_time elapses and the command has not
403 returned an output containing expected yet.
405 # Query the device with the command
409 while not success
and (attempts
*wait_period
) < wait_time
:
410 # assume the command will always contain expected in the success case
412 output
= self
.SendShellCommand(command
, retry_count
=1)
413 if ((not invert
and expected
in output
)
414 or (invert
and expected
not in output
)):
416 except errors
.AbortError
, e
:
422 time
.sleep(wait_period
)
426 raise errors
.WaitForResponseTimedOutError()
428 def WaitForBootComplete(self
, wait_time
=120):
429 """Waits for targeted device's bootcomplete flag to be set.
432 wait_time: time in seconds to wait
435 WaitForResponseTimedOutError if wait_time elapses and pm still does not
438 logger
.Log("Waiting for boot complete...")
439 self
.SendCommand("wait-for-device")
440 # Now the device is there, but may not be running.
441 # Query the package manager with a basic command
442 boot_complete
= False
445 while not boot_complete
and (attempts
*wait_period
) < wait_time
:
446 output
= self
.SendShellCommand("getprop dev.bootcomplete", retry_count
=1)
447 output
= output
.strip()
451 time
.sleep(wait_period
)
453 if not boot_complete
:
454 raise errors
.WaitForResponseTimedOutError(
455 "dev.bootcomplete flag was not set after %s seconds" % wait_time
)
457 def Sync(self
, retry_count
=3, runtime_restart
=False):
458 """Perform a adb sync.
460 Blocks until device package manager is responding.
463 retry_count: number of times to retry sync before failing
464 runtime_restart: stop runtime during sync and restart afterwards, useful
465 for syncing system libraries (core, framework etc)
468 WaitForResponseTimedOutError if package manager does not respond
469 AbortError if unrecoverable error occurred
474 self
.SendShellCommand("setprop ro.monkey 1", retry_count
=retry_count
)
475 # manual rest bootcomplete flag
476 self
.SendShellCommand("setprop dev.bootcomplete 0",
477 retry_count
=retry_count
)
478 self
.SendShellCommand("stop", retry_count
=retry_count
)
481 output
= self
.SendCommand("sync", retry_count
=retry_count
)
482 except errors
.AbortError
, e
:
485 if "Read-only file system" in output
:
486 logger
.SilentLog(output
)
487 logger
.Log("Remounting read-only filesystem")
488 self
.SendCommand("remount")
489 output
= self
.SendCommand("sync", retry_count
=retry_count
)
490 elif "No space left on device" in output
:
491 logger
.SilentLog(output
)
492 logger
.Log("Restarting device runtime")
493 self
.SendShellCommand("stop", retry_count
=retry_count
)
494 output
= self
.SendCommand("sync", retry_count
=retry_count
)
495 self
.SendShellCommand("start", retry_count
=retry_count
)
496 elif error
is not None:
497 # exception occurred that cannot be recovered from
499 logger
.SilentLog(output
)
501 # start runtime and wait till boot complete flag is set
502 self
.SendShellCommand("start", retry_count
=retry_count
)
503 self
.WaitForBootComplete()
504 # press the MENU key, this will disable key guard if runtime is started
505 # with ro.monkey set to 1
506 self
.SendShellCommand("input keyevent 82", retry_count
=retry_count
)
508 self
.WaitForDevicePm()
511 def GetSerialNumber(self
):
512 """Returns the serial number of the targeted device."""
513 return self
.SendCommand("get-serialno").strip()