blob: 451d04644125112373e757079f2eb2bcb5fea334 [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
Brett Chabotccae47d2010-06-14 15:19:25 -0700151 def EnableAdbRoot(self):
152 """Enable adb root on device."""
153 output = self.SendCommand("root")
154 if "adbd is already running as root" in output:
155 return True
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")
159 return True
160 else:
161 logger.Log("Unrecognized output from adb root: %s" % output)
162 return False
163
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800164 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.
168
169 Equivalent to StartInstrumentation, except instrumentation path is
170 separated into its package and runner components.
171 """
172 instrumentation_path = "%s/%s" % (package_name, runner_name)
Brett Chabotae68f1a2009-05-28 18:29:24 -0700173 return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_time,
174 no_window_animation=no_window_animation,
175 instrumentation_args=instrumentation_args)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800176
177 def StartInstrumentation(
178 self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
179 profile=False, instrumentation_args={}):
180
181 """Runs an instrumentation class on the target.
182
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
186 exceptions.
187
188 Args:
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
194 or disabled
195 profile: If True, profiling will be turned on for the instrumentation.
196 instrumentation_args: Dictionary of key value bundle arguments to pass to
197 instrumentation.
198
199 Returns:
200 (test_results, inst_finished_bundle)
201
202 test_results: a list of TestResults
203 inst_finished_bundle (dict): Key/value pairs contained in the bundle that
204 is passed into ActivityManager.finishInstrumentation(). Included in this
205 bundle is the return code of the Instrumentation process, any error
206 codes reported by the activity manager, and any results explicitly added
207 by the instrumentation code.
208
209 Raises:
210 WaitForResponseTimedOutError: if timeout occurred while waiting for
211 response to adb instrument command
212 DeviceUnresponsiveError: if device system process is not responding
213 InstrumentationError: if instrumentation failed to run
214 """
215
216 command_string = self._BuildInstrumentationCommandPath(
217 instrumentation_path, no_window_animation=no_window_animation,
218 profile=profile, raw_mode=True,
219 instrumentation_args=instrumentation_args)
Brett Chabotae68f1a2009-05-28 18:29:24 -0700220 logger.Log(command_string)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800221 (test_results, inst_finished_bundle) = (
222 am_instrument_parser.ParseAmInstrumentOutput(
223 self.SendShellCommand(command_string, timeout_time=timeout_time,
224 retry_count=2)))
225
226 if "code" not in inst_finished_bundle:
227 raise errors.InstrumentationError("no test results... device setup "
228 "correctly?")
229
230 if inst_finished_bundle["code"] == "0":
231 short_msg_result = "no error message"
232 if "shortMsg" in inst_finished_bundle:
233 short_msg_result = inst_finished_bundle["shortMsg"]
Brett Chabotae68f1a2009-05-28 18:29:24 -0700234 logger.Log("Error! Test run failed: %s" % short_msg_result)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800235 raise errors.InstrumentationError(short_msg_result)
236
237 if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
238 logger.Log("INSTRUMENTATION ABORTED!")
239 raise errors.DeviceUnresponsiveError
240
241 return (test_results, inst_finished_bundle)
242
243 def StartInstrumentationNoResults(
244 self, package_name, runner_name, no_window_animation=False,
245 raw_mode=False, instrumentation_args={}):
246 """Runs instrumentation and dumps output to stdout.
247
248 Equivalent to StartInstrumentation, but will dump instrumentation
249 'normal' output to stdout, instead of parsing return results. Command will
250 never timeout.
251 """
252 adb_command_string = self.PreviewInstrumentationCommand(
253 package_name, runner_name, no_window_animation=no_window_animation,
254 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
255 logger.Log(adb_command_string)
256 run_command.RunCommand(adb_command_string, return_output=False)
257
258 def PreviewInstrumentationCommand(
259 self, package_name, runner_name, no_window_animation=False,
260 raw_mode=False, instrumentation_args={}):
261 """Returns a string of adb command that will be executed."""
262 inst_command_string = self._BuildInstrumentationCommand(
263 package_name, runner_name, no_window_animation=no_window_animation,
264 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
265 command_string = "adb %s shell %s" % (self._target_arg, inst_command_string)
266 return command_string
267
268 def _BuildInstrumentationCommand(
269 self, package, runner_name, no_window_animation=False, profile=False,
270 raw_mode=True, instrumentation_args={}):
271 instrumentation_path = "%s/%s" % (package, runner_name)
272
273 return self._BuildInstrumentationCommandPath(
274 instrumentation_path, no_window_animation=no_window_animation,
275 profile=profile, raw_mode=raw_mode,
276 instrumentation_args=instrumentation_args)
277
278 def _BuildInstrumentationCommandPath(
279 self, instrumentation_path, no_window_animation=False, profile=False,
280 raw_mode=True, instrumentation_args={}):
281 command_string = "am instrument"
282 if no_window_animation:
283 command_string += " --no_window_animation"
284 if profile:
285 self._CreateTraceDir()
286 command_string += (
287 " -p %s/%s.dmtrace" %
288 (self.DEVICE_TRACE_DIR, instrumentation_path.split(".")[-1]))
289
290 for key, value in instrumentation_args.items():
Brett Chabote0bf8162009-06-29 13:55:30 -0700291 command_string += " -e %s '%s'" % (key, value)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800292 if raw_mode:
293 command_string += " -r"
294 command_string += " -w %s" % instrumentation_path
295 return command_string
296
297 def _CreateTraceDir(self):
298 ls_response = self.SendShellCommand("ls /data/trace")
299 if ls_response.strip("#").strip(string.whitespace) != "":
300 self.SendShellCommand("create /data/trace", "mkdir /data/trace")
301 self.SendShellCommand("make /data/trace world writeable",
302 "chmod 777 /data/trace")
303
304 def WaitForDevicePm(self, wait_time=120):
305 """Waits for targeted device's package manager to be up.
306
307 Args:
308 wait_time: time in seconds to wait
309
310 Raises:
311 WaitForResponseTimedOutError if wait_time elapses and pm still does not
312 respond.
313 """
Brett Chabot72731f32009-03-31 11:14:05 -0700314 logger.Log("Waiting for device package manager...")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800315 self.SendCommand("wait-for-device")
316 # Now the device is there, but may not be running.
317 # Query the package manager with a basic command
318 pm_found = False
319 attempts = 0
320 wait_period = 5
321 while not pm_found and (attempts*wait_period) < wait_time:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700322 # assume the 'adb shell pm path android' command will always
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800323 # return 'package: something' in the success case
324 output = self.SendShellCommand("pm path android", retry_count=1)
325 if "package:" in output:
326 pm_found = True
327 else:
328 time.sleep(wait_period)
329 attempts += 1
330 if not pm_found:
Brett Chabot72731f32009-03-31 11:14:05 -0700331 raise errors.WaitForResponseTimedOutError(
332 "Package manager did not respond after %s seconds" % wait_time)
Brett Chabot97d5c502009-06-04 13:50:55 -0700333
334 def WaitForInstrumentation(self, package_name, runner_name, wait_time=120):
335 """Waits for given instrumentation to be present on device
336
337 Args:
338 wait_time: time in seconds to wait
339
340 Raises:
341 WaitForResponseTimedOutError if wait_time elapses and instrumentation
342 still not present.
343 """
344 instrumentation_path = "%s/%s" % (package_name, runner_name)
345 logger.Log("Waiting for instrumentation to be present")
346 # Query the package manager
347 inst_found = False
348 attempts = 0
349 wait_period = 5
350 while not inst_found and (attempts*wait_period) < wait_time:
351 # assume the 'adb shell pm list instrumentation'
352 # return 'instrumentation: something' in the success case
353 try:
354 output = self.SendShellCommand("pm list instrumentation | grep %s"
355 % instrumentation_path, retry_count=1)
356 if "instrumentation:" in output:
357 inst_found = True
358 except errors.AbortError, e:
359 # ignore
360 pass
361 if not inst_found:
362 time.sleep(wait_period)
363 attempts += 1
364 if not inst_found:
365 logger.Log(
366 "Could not find instrumentation %s on device. Does the "
367 "instrumentation in test's AndroidManifest.xml match definition"
368 "in test_defs.xml?" % instrumentation_path)
369 raise errors.WaitForResponseTimedOutError()
370
Guang Zhu863870c2010-04-15 10:48:26 -0700371 def WaitForBootComplete(self, wait_time=120):
372 """Waits for targeted device's bootcomplete flag to be set.
373
374 Args:
375 wait_time: time in seconds to wait
376
377 Raises:
378 WaitForResponseTimedOutError if wait_time elapses and pm still does not
379 respond.
380 """
381 logger.Log("Waiting for boot complete...")
382 self.SendCommand("wait-for-device")
383 # Now the device is there, but may not be running.
384 # Query the package manager with a basic command
385 boot_complete = False
386 attempts = 0
387 wait_period = 5
388 while not boot_complete and (attempts*wait_period) < wait_time:
389 output = self.SendShellCommand("getprop dev.bootcomplete", retry_count=1)
390 output = output.strip()
391 if output == "1":
392 boot_complete = True
393 else:
394 time.sleep(wait_period)
395 attempts += 1
396 if not boot_complete:
397 raise errors.WaitForResponseTimedOutError(
398 "dev.bootcomplete flag was not set after %s seconds" % wait_time)
399
400 def Sync(self, retry_count=3, runtime_restart=False):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800401 """Perform a adb sync.
Brett Chabot764d3fa2009-06-25 17:57:31 -0700402
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800403 Blocks until device package manager is responding.
Brett Chabot764d3fa2009-06-25 17:57:31 -0700404
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800405 Args:
406 retry_count: number of times to retry sync before failing
Guang Zhu863870c2010-04-15 10:48:26 -0700407 runtime_restart: stop runtime during sync and restart afterwards, useful
408 for syncing system libraries (core, framework etc)
Brett Chabot764d3fa2009-06-25 17:57:31 -0700409
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800410 Raises:
411 WaitForResponseTimedOutError if package manager does not respond
Brett Chabot8a101cb2009-05-05 12:56:39 -0700412 AbortError if unrecoverable error occurred
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800413 """
Brett Chabot8a101cb2009-05-05 12:56:39 -0700414 output = ""
415 error = None
Guang Zhu863870c2010-04-15 10:48:26 -0700416 if runtime_restart:
417 self.SendShellCommand("setprop ro.monkey 1", retry_count=retry_count)
418 # manual rest bootcomplete flag
419 self.SendShellCommand("setprop dev.bootcomplete 0",
420 retry_count=retry_count)
421 self.SendShellCommand("stop", retry_count=retry_count)
422
Brett Chabot8a101cb2009-05-05 12:56:39 -0700423 try:
424 output = self.SendCommand("sync", retry_count=retry_count)
425 except errors.AbortError, e:
426 error = e
427 output = e.msg
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800428 if "Read-only file system" in output:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700429 logger.SilentLog(output)
Brett Chabot72731f32009-03-31 11:14:05 -0700430 logger.Log("Remounting read-only filesystem")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800431 self.SendCommand("remount")
432 output = self.SendCommand("sync", retry_count=retry_count)
Brett Chabot8a101cb2009-05-05 12:56:39 -0700433 elif "No space left on device" in output:
Brett Chabot764d3fa2009-06-25 17:57:31 -0700434 logger.SilentLog(output)
Brett Chabot72731f32009-03-31 11:14:05 -0700435 logger.Log("Restarting device runtime")
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800436 self.SendShellCommand("stop", retry_count=retry_count)
437 output = self.SendCommand("sync", retry_count=retry_count)
438 self.SendShellCommand("start", retry_count=retry_count)
Brett Chabot8a101cb2009-05-05 12:56:39 -0700439 elif error is not None:
440 # exception occurred that cannot be recovered from
441 raise error
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800442 logger.SilentLog(output)
Guang Zhu863870c2010-04-15 10:48:26 -0700443 if runtime_restart:
444 # start runtime and wait till boot complete flag is set
445 self.SendShellCommand("start", retry_count=retry_count)
446 self.WaitForBootComplete()
447 # press the MENU key, this will disable key guard if runtime is started
448 # with ro.monkey set to 1
449 self.SendShellCommand("input keyevent 82", retry_count=retry_count)
450 else:
451 self.WaitForDevicePm()
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800452 return output
Brett Chabot72731f32009-03-31 11:14:05 -0700453
Brett Chabot764d3fa2009-06-25 17:57:31 -0700454 def GetSerialNumber(self):
455 """Returns the serial number of the targeted device."""
456 return self.SendCommand("get-serialno").strip()