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 DEVICE_TRACE_DIR
= "/data/test_results/"
39 def __init__(self
, adb_path
='adb'):
43 adb_path: Absolute path to the adb binary that should be used. Defaults
44 to the adb in the environment path.
46 self
._adb
_path
= adb_path
47 # argument to pass to adb, to direct command to specific device
50 def SetEmulatorTarget(self
):
51 """Direct all future commands to the only running emulator."""
52 self
._target
_arg
= "-e"
54 def SetDeviceTarget(self
):
55 """Direct all future commands to the only connected USB device."""
56 self
._target
_arg
= "-d"
58 def SetTargetSerial(self
, serial
):
59 """Direct all future commands to Android target with the given serial."""
60 self
._target
_arg
= "-s %s" % serial
62 def SendCommand(self
, command_string
, timeout_time
=20, retry_count
=3):
63 """Send a command via adb.
66 command_string: adb command to run
67 timeout_time: number of seconds to wait for command to respond before
69 retry_count: number of times to retry command before raising
70 WaitForResponseTimedOutError
72 string output of command
75 WaitForResponseTimedOutError if device does not respond to command within time
77 adb_cmd
= "%s %s %s" % (self
._adb
_path
, self
._target
_arg
, command_string
)
78 logger
.SilentLog("about to run %s" % adb_cmd
)
79 return run_command
.RunCommand(adb_cmd
, timeout_time
=timeout_time
,
80 retry_count
=retry_count
)
82 def SendShellCommand(self
, cmd
, timeout_time
=20, retry_count
=3):
83 """Send a adb shell command.
86 cmd: adb shell command to run
87 timeout_time: number of seconds to wait for command to respond before
89 retry_count: number of times to retry command before raising
90 WaitForResponseTimedOutError
93 string output of command
96 WaitForResponseTimedOutError: if device does not respond to command
98 return self
.SendCommand("shell %s" % cmd
, timeout_time
=timeout_time
,
99 retry_count
=retry_count
)
101 def BugReport(self
, path
):
102 """Dumps adb bugreport to the file specified by the path.
105 path: Path of the file where adb bugreport is dumped to.
107 bug_output
= self
.SendShellCommand("bugreport", timeout_time
=60)
108 bugreport_file
= open(path
, "w")
109 bugreport_file
.write(bug_output
)
110 bugreport_file
.close()
112 def Push(self
, src
, dest
):
113 """Pushes the file src onto the device at dest.
116 src: file path of host file to push
117 dest: destination absolute file path on device
119 self
.SendCommand("push %s %s" % (src
, dest
), timeout_time
=60)
121 def Pull(self
, src
, dest
):
122 """Pulls the file src on the device onto dest on the host.
125 src: absolute file path of file on device to pull
126 dest: destination file path on host
129 True if success and False otherwise.
131 # Create the base dir if it doesn't exist already
132 if not os
.path
.exists(os
.path
.dirname(dest
)):
133 os
.makedirs(os
.path
.dirname(dest
))
135 if self
.DoesFileExist(src
):
136 self
.SendCommand("pull %s %s" % (src
, dest
), timeout_time
=60)
139 logger
.Log("ADB Pull Failed: Source file %s does not exist." % src
)
142 def DoesFileExist(self
, src
):
143 """Checks if the given path exists on device target.
146 src: file path to be checked.
152 output
= self
.SendShellCommand("ls %s" % src
)
153 error
= "No such file or directory"
159 def EnableAdbRoot(self
):
160 """Enable adb root on device."""
161 output
= self
.SendCommand("root")
162 if "adbd is already running as root" in output
:
164 elif "restarting adbd as root" in output
:
165 # device will disappear from adb, wait for it to come back
166 self
.SendCommand("wait-for-device")
169 logger
.Log("Unrecognized output from adb root: %s" % output
)
172 def StartInstrumentationForPackage(
173 self
, package_name
, runner_name
, timeout_time
=60*10,
174 no_window_animation
=False, instrumentation_args
={}):
175 """Run instrumentation test for given package and runner.
177 Equivalent to StartInstrumentation, except instrumentation path is
178 separated into its package and runner components.
180 instrumentation_path
= "%s/%s" % (package_name
, runner_name
)
181 return self
.StartInstrumentation(instrumentation_path
, timeout_time
=timeout_time
,
182 no_window_animation
=no_window_animation
,
183 instrumentation_args
=instrumentation_args
)
185 def StartInstrumentation(
186 self
, instrumentation_path
, timeout_time
=60*10, no_window_animation
=False,
187 profile
=False, instrumentation_args
={}, silent_log
=False):
189 """Runs an instrumentation class on the target.
191 Returns a dictionary containing the key value pairs from the
192 instrumentations result bundle and a list of TestResults. Also handles the
193 interpreting of error output from the device and raises the necessary
197 instrumentation_path: string. It should be the fully classified package
198 name, and instrumentation test runner, separated by "/"
199 e.g. com.android.globaltimelaunch/.GlobalTimeLaunch
200 timeout_time: Timeout value for the am command.
201 no_window_animation: boolean, Whether you want window animations enabled
203 profile: If True, profiling will be turned on for the instrumentation.
204 instrumentation_args: Dictionary of key value bundle arguments to pass to
206 silent_log: If True, the invocation of the instrumentation test runner
210 (test_results, inst_finished_bundle)
212 test_results: a list of TestResults
213 inst_finished_bundle (dict): Key/value pairs contained in the bundle that
214 is passed into ActivityManager.finishInstrumentation(). Included in this
215 bundle is the return code of the Instrumentation process, any error
216 codes reported by the activity manager, and any results explicitly added
217 by the instrumentation code.
220 WaitForResponseTimedOutError: if timeout occurred while waiting for
221 response to adb instrument command
222 DeviceUnresponsiveError: if device system process is not responding
223 InstrumentationError: if instrumentation failed to run
226 command_string
= self
._BuildInstrumentationCommandPath
(
227 instrumentation_path
, no_window_animation
=no_window_animation
,
228 profile
=profile
, raw_mode
=True,
229 instrumentation_args
=instrumentation_args
)
231 logger
.SilentLog(command_string
)
233 logger
.Log(command_string
)
234 (test_results
, inst_finished_bundle
) = (
235 am_instrument_parser
.ParseAmInstrumentOutput(
236 self
.SendShellCommand(command_string
, timeout_time
=timeout_time
,
238 if "code" not in inst_finished_bundle
:
239 logger
.Log('No code available. inst_finished_bundle contains: %s '
240 % inst_finished_bundle
)
241 raise errors
.InstrumentationError("no test results... device setup "
244 if inst_finished_bundle
["code"] == "0":
245 long_msg_result
= "no error message"
246 if "longMsg" in inst_finished_bundle
:
247 long_msg_result
= inst_finished_bundle
["longMsg"]
248 logger
.Log("Error! Test run failed: %s" % long_msg_result
)
249 raise errors
.InstrumentationError(long_msg_result
)
251 if "INSTRUMENTATION_ABORTED" in inst_finished_bundle
:
252 logger
.Log("INSTRUMENTATION ABORTED!")
253 raise errors
.DeviceUnresponsiveError
255 return (test_results
, inst_finished_bundle
)
257 def StartInstrumentationNoResults(
258 self
, package_name
, runner_name
, no_window_animation
=False,
259 raw_mode
=False, instrumentation_args
={}):
260 """Runs instrumentation and dumps output to stdout.
262 Equivalent to StartInstrumentation, but will dump instrumentation
263 'normal' output to stdout, instead of parsing return results. Command will
266 adb_command_string
= self
.PreviewInstrumentationCommand(
267 package_name
, runner_name
, no_window_animation
=no_window_animation
,
268 raw_mode
=raw_mode
, instrumentation_args
=instrumentation_args
)
269 logger
.Log(adb_command_string
)
270 run_command
.RunCommand(adb_command_string
, return_output
=False)
272 def PreviewInstrumentationCommand(
273 self
, package_name
, runner_name
, no_window_animation
=False,
274 raw_mode
=False, instrumentation_args
={}):
275 """Returns a string of adb command that will be executed."""
276 inst_command_string
= self
._BuildInstrumentationCommand
(
277 package_name
, runner_name
, no_window_animation
=no_window_animation
,
278 raw_mode
=raw_mode
, instrumentation_args
=instrumentation_args
)
279 command_string
= "adb %s shell %s" % (self
._target
_arg
, inst_command_string
)
280 return command_string
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
)
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
)
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"
299 self
._CreateTraceDir
()
301 " -p %s/%s.dmtrace" %
302 (self
.DEVICE_TRACE_DIR
, instrumentation_path
.split(".")[-1]))
304 for key
, value
in instrumentation_args
.items():
305 command_string
+= " -e %s '%s'" % (key
, value
)
307 command_string
+= " -r"
308 command_string
+= " -w %s" % instrumentation_path
309 return command_string
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")
318 def WaitForDevicePm(self
, wait_time
=120):
319 """Waits for targeted device's package manager to be up.
322 wait_time: time in seconds to wait
325 WaitForResponseTimedOutError if wait_time elapses and pm still does not
328 logger
.Log("Waiting for device package manager...")
329 self
.SendCommand("wait-for-device", timeout_time
=wait_time
, retry_count
=0)
330 # Now the device is there, but may not be running.
331 # Query the package manager with a basic command
333 self
._WaitForShellCommandContents
("pm path android", "package:",
335 except errors
.WaitForResponseTimedOutError
:
336 raise errors
.WaitForResponseTimedOutError(
337 "Package manager did not respond after %s seconds" % wait_time
)
339 def WaitForInstrumentation(self
, package_name
, runner_name
, wait_time
=120):
340 """Waits for given instrumentation to be present on device
343 wait_time: time in seconds to wait
346 WaitForResponseTimedOutError if wait_time elapses and instrumentation
349 instrumentation_path
= "%s/%s" % (package_name
, runner_name
)
350 logger
.Log("Waiting for instrumentation to be present")
351 # Query the package manager
353 command
= "pm list instrumentation | grep %s" % instrumentation_path
354 self
._WaitForShellCommandContents
(command
, "instrumentation:", wait_time
,
356 except errors
.WaitForResponseTimedOutError
:
358 "Could not find instrumentation %s on device. Does the "
359 "instrumentation in test's AndroidManifest.xml match definition"
360 "in test_defs.xml?" % instrumentation_path
)
363 def WaitForProcess(self
, name
, wait_time
=120):
364 """Wait until a process is running on the device.
367 name: the process name as it appears in `ps`
368 wait_time: time in seconds to wait
371 WaitForResponseTimedOutError if wait_time elapses and the process is
374 logger
.Log("Waiting for process %s" % name
)
375 self
.SendCommand("wait-for-device")
376 self
._WaitForShellCommandContents
("ps", name
, wait_time
)
378 def WaitForProcessEnd(self
, name
, wait_time
=120):
379 """Wait until a process is no longer running on the device.
382 name: the process name as it appears in `ps`
383 wait_time: time in seconds to wait
386 WaitForResponseTimedOutError if wait_time elapses and the process is
389 logger
.Log("Waiting for process %s to end" % name
)
390 self
._WaitForShellCommandContents
("ps", name
, wait_time
, invert
=True)
392 def _WaitForShellCommandContents(self
, command
, expected
, wait_time
,
393 raise_abort
=True, invert
=False):
394 """Wait until the response to a command contains a given output.
396 Assumes that a only successful execution of "adb shell <command>" contains
397 the substring expected. Assumes that a device is present.
400 command: adb shell command to execute
401 expected: the string that should appear to consider the
403 wait_time: time in seconds to wait
404 raise_abort: if False, retry when executing the command raises an
405 AbortError, rather than failing.
406 invert: if True, wait until the command output no longer contains the
410 WaitForResponseTimedOutError: If wait_time elapses and the command has not
411 returned an output containing expected yet.
413 # Query the device with the command
417 while not success
and (attempts
*wait_period
) < wait_time
:
418 # assume the command will always contain expected in the success case
420 output
= self
.SendShellCommand(command
, retry_count
=1,
421 timeout_time
=wait_time
)
422 if ((not invert
and expected
in output
)
423 or (invert
and expected
not in output
)):
425 except errors
.AbortError
, e
:
431 time
.sleep(wait_period
)
435 raise errors
.WaitForResponseTimedOutError()
437 def WaitForBootComplete(self
, wait_time
=120):
438 """Waits for targeted device's bootcomplete flag to be set.
441 wait_time: time in seconds to wait
444 WaitForResponseTimedOutError if wait_time elapses and pm still does not
447 logger
.Log("Waiting for boot complete...")
448 self
.SendCommand("wait-for-device")
449 # Now the device is there, but may not be running.
450 # Query the package manager with a basic command
451 boot_complete
= False
454 while not boot_complete
and (attempts
*wait_period
) < wait_time
:
455 output
= self
.SendShellCommand("getprop dev.bootcomplete", retry_count
=1)
456 output
= output
.strip()
460 time
.sleep(wait_period
)
462 if not boot_complete
:
463 raise errors
.WaitForResponseTimedOutError(
464 "dev.bootcomplete flag was not set after %s seconds" % wait_time
)
466 def Sync(self
, retry_count
=3, runtime_restart
=False):
467 """Perform a adb sync.
469 Blocks until device package manager is responding.
472 retry_count: number of times to retry sync before failing
473 runtime_restart: stop runtime during sync and restart afterwards, useful
474 for syncing system libraries (core, framework etc)
477 WaitForResponseTimedOutError if package manager does not respond
478 AbortError if unrecoverable error occurred
483 self
.SendShellCommand("setprop ro.monkey 1", retry_count
=retry_count
)
484 # manual rest bootcomplete flag
485 self
.SendShellCommand("setprop dev.bootcomplete 0",
486 retry_count
=retry_count
)
487 self
.SendShellCommand("stop", retry_count
=retry_count
)
490 output
= self
.SendCommand("sync", retry_count
=retry_count
)
491 except errors
.AbortError
, e
:
494 if "Read-only file system" in output
:
495 logger
.SilentLog(output
)
496 logger
.Log("Remounting read-only filesystem")
497 self
.SendCommand("remount")
498 output
= self
.SendCommand("sync", retry_count
=retry_count
)
499 elif "No space left on device" in output
:
500 logger
.SilentLog(output
)
501 logger
.Log("Restarting device runtime")
502 self
.SendShellCommand("stop", retry_count
=retry_count
)
503 output
= self
.SendCommand("sync", retry_count
=retry_count
)
504 self
.SendShellCommand("start", retry_count
=retry_count
)
505 elif error
is not None:
506 # exception occurred that cannot be recovered from
508 logger
.SilentLog(output
)
510 # start runtime and wait till boot complete flag is set
511 self
.SendShellCommand("start", retry_count
=retry_count
)
512 self
.WaitForBootComplete()
513 # press the MENU key, this will disable key guard if runtime is started
514 # with ro.monkey set to 1
515 self
.SendShellCommand("input keyevent 82", retry_count
=retry_count
)
517 self
.WaitForDevicePm()
520 def GetSerialNumber(self
):
521 """Returns the serial number of the targeted device."""
522 return self
.SendCommand("get-serialno").strip()