1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """This module wraps Android's adb tool.
7 This is a thin wrapper around the adb interface. Any additional complexity
8 should be delegated to a higher level (ex. DeviceUtils).
16 from pylib
import cmd_helper
17 from pylib
import constants
18 from pylib
.device
import decorators
19 from pylib
.device
import device_errors
20 from pylib
.utils
import timeout_retry
27 def _VerifyLocalFileExists(path
):
28 """Verifies a local file exists.
31 path: Path to the local file.
34 IOError: If the file doesn't exist.
36 if not os
.path
.exists(path
):
37 raise IOError(errno
.ENOENT
, os
.strerror(errno
.ENOENT
), path
)
40 DeviceStat
= collections
.namedtuple('DeviceStat',
41 ['st_mode', 'st_size', 'st_time'])
44 class AdbWrapper(object):
45 """A wrapper around a local Android Debug Bridge executable."""
47 def __init__(self
, device_serial
):
48 """Initializes the AdbWrapper.
51 device_serial: The device serial number as a string.
54 raise ValueError('A device serial must be specified')
55 self
._device
_serial
= str(device_serial
)
57 # pylint: disable=unused-argument
59 def _BuildAdbCmd(cls
, args
, device_serial
, cpu_affinity
=None):
60 if cpu_affinity
is not None:
61 cmd
= ['taskset', '-c', str(cpu_affinity
)]
64 cmd
.append(constants
.GetAdbPath())
65 if device_serial
is not None:
66 cmd
.extend(['-s', device_serial
])
69 # pylint: enable=unused-argument
71 # pylint: disable=unused-argument
73 @decorators.WithTimeoutAndRetries
74 def _RunAdbCmd(cls
, args
, timeout
=None, retries
=None, device_serial
=None,
75 check_error
=True, cpu_affinity
=None):
76 status
, output
= cmd_helper
.GetCmdStatusAndOutputWithTimeout(
77 cls
._BuildAdbCmd
(args
, device_serial
, cpu_affinity
=cpu_affinity
),
78 timeout_retry
.CurrentTimeoutThread().GetRemainingTime())
80 raise device_errors
.AdbCommandFailedError(
81 args
, output
, status
, device_serial
)
82 # This catches some errors, including when the device drops offline;
83 # unfortunately adb is very inconsistent with error reporting so many
84 # command failures present differently.
85 if check_error
and output
.startswith('error:'):
86 raise device_errors
.AdbCommandFailedError(args
, output
)
88 # pylint: enable=unused-argument
90 def _RunDeviceAdbCmd(self
, args
, timeout
, retries
, check_error
=True):
91 """Runs an adb command on the device associated with this object.
94 args: A list of arguments to adb.
95 timeout: Timeout in seconds.
96 retries: Number of retries.
97 check_error: Check that the command doesn't return an error message. This
98 does NOT check the exit status of shell commands.
101 The output of the command.
103 return self
._RunAdbCmd
(args
, timeout
=timeout
, retries
=retries
,
104 device_serial
=self
._device
_serial
,
105 check_error
=check_error
)
107 def _IterRunDeviceAdbCmd(self
, args
, timeout
):
108 """Runs an adb command and returns an iterator over its output lines.
111 args: A list of arguments to adb.
112 timeout: Timeout in seconds.
115 The output of the command line by line.
117 return cmd_helper
.IterCmdOutputLines(
118 self
._BuildAdbCmd
(args
, self
._device
_serial
), timeout
=timeout
)
120 def __eq__(self
, other
):
121 """Consider instances equal if they refer to the same device.
124 other: The instance to compare equality with.
127 True if the instances are considered equal, false otherwise.
129 return self
._device
_serial
== str(other
)
132 """The string representation of an instance.
135 The device serial number as a string.
137 return self
._device
_serial
140 return '%s(\'%s\')' % (self
.__class
__.__name
__, self
)
142 # pylint: disable=unused-argument
144 def IsServerOnline(cls
):
145 status
, output
= cmd_helper
.GetCmdStatusAndOutput(['pgrep', 'adb'])
146 output
= [int(x
) for x
in output
.split()]
147 logging
.info('PIDs for adb found: %r', output
)
149 # pylint: enable=unused-argument
152 def KillServer(cls
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
153 cls
._RunAdbCmd
(['kill-server'], timeout
=timeout
, retries
=retries
)
156 def StartServer(cls
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
157 # CPU affinity is used to reduce adb instability http://crbug.com/268450
158 cls
._RunAdbCmd
(['start-server'], timeout
=timeout
, retries
=retries
,
161 # TODO(craigdh): Determine the filter criteria that should be supported.
163 def GetDevices(cls
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
164 """Get the list of active attached devices.
167 timeout: (optional) Timeout per try in seconds.
168 retries: (optional) Number of retries to attempt.
171 AdbWrapper instances.
173 output
= cls
._RunAdbCmd
(['devices'], timeout
=timeout
, retries
=retries
)
174 lines
= [line
.split() for line
in output
.splitlines()]
175 return [AdbWrapper(line
[0]) for line
in lines
176 if len(line
) == 2 and line
[1] == 'device']
178 def GetDeviceSerial(self
):
179 """Gets the device serial number associated with this object.
182 Device serial number as a string.
184 return self
._device
_serial
186 def Push(self
, local
, remote
, timeout
=60*5, retries
=_DEFAULT_RETRIES
):
187 """Pushes a file from the host to the device.
190 local: Path on the host filesystem.
191 remote: Path on the device filesystem.
192 timeout: (optional) Timeout per try in seconds.
193 retries: (optional) Number of retries to attempt.
195 _VerifyLocalFileExists(local
)
196 self
._RunDeviceAdbCmd
(['push', local
, remote
], timeout
, retries
)
198 def Pull(self
, remote
, local
, timeout
=60*5, retries
=_DEFAULT_RETRIES
):
199 """Pulls a file from the device to the host.
202 remote: Path on the device filesystem.
203 local: Path on the host filesystem.
204 timeout: (optional) Timeout per try in seconds.
205 retries: (optional) Number of retries to attempt.
207 cmd
= ['pull', remote
, local
]
208 self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
210 _VerifyLocalFileExists(local
)
212 raise device_errors
.AdbCommandFailedError(
213 cmd
, 'File not found on host: %s' % local
, device_serial
=str(self
))
215 def Shell(self
, command
, expect_status
=0, timeout
=_DEFAULT_TIMEOUT
,
216 retries
=_DEFAULT_RETRIES
):
217 """Runs a shell command on the device.
220 command: A string with the shell command to run.
221 expect_status: (optional) Check that the command's exit status matches
222 this value. Default is 0. If set to None the test is skipped.
223 timeout: (optional) Timeout per try in seconds.
224 retries: (optional) Number of retries to attempt.
227 The output of the shell command as a string.
230 device_errors.AdbCommandFailedError: If the exit status doesn't match
233 if expect_status
is None:
234 args
= ['shell', command
]
236 args
= ['shell', '%s; echo %%$?;' % command
.rstrip()]
237 output
= self
._RunDeviceAdbCmd
(args
, timeout
, retries
, check_error
=False)
238 if expect_status
is not None:
239 output_end
= output
.rfind('%')
241 # causes the status string to become empty and raise a ValueError
242 output_end
= len(output
)
245 status
= int(output
[output_end
+1:])
247 logging
.warning('exit status of shell command %r missing.', command
)
248 raise device_errors
.AdbShellCommandFailedError(
249 command
, output
, status
=None, device_serial
=self
._device
_serial
)
250 output
= output
[:output_end
]
251 if status
!= expect_status
:
252 raise device_errors
.AdbShellCommandFailedError(
253 command
, output
, status
=status
, device_serial
=self
._device
_serial
)
256 def IterShell(self
, command
, timeout
):
257 """Runs a shell command and returns an iterator over its output lines.
260 command: A string with the shell command to run.
261 timeout: Timeout in seconds.
264 The output of the command line by line.
266 args
= ['shell', command
]
267 return cmd_helper
.IterCmdOutputLines(
268 self
._BuildAdbCmd
(args
, self
._device
_serial
), timeout
=timeout
)
270 def Ls(self
, path
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
271 """List the contents of a directory on the device.
274 path: Path on the device filesystem.
275 timeout: (optional) Timeout per try in seconds.
276 retries: (optional) Number of retries to attempt.
279 A list of pairs (filename, stat) for each file found in the directory,
280 where the stat object has the properties: st_mode, st_size, and st_time.
283 AdbCommandFailedError if |path| does not specify a valid and accessible
284 directory in the device.
287 cols
= line
.split(None, 3)
288 filename
= cols
.pop()
289 stat
= DeviceStat(*[int(num
, base
=16) for num
in cols
])
290 return (filename
, stat
)
293 lines
= self
._RunDeviceAdbCmd
(
294 cmd
, timeout
=timeout
, retries
=retries
).splitlines()
296 return [ParseLine(line
) for line
in lines
]
298 raise device_errors
.AdbCommandFailedError(
299 cmd
, 'path does not specify an accessible directory in the device',
300 device_serial
=self
._device
_serial
)
302 def Logcat(self
, clear
=False, dump
=False, filter_specs
=None,
303 logcat_format
=None, ring_buffer
=None, timeout
=None,
304 retries
=_DEFAULT_RETRIES
):
305 """Get an iterable over the logcat output.
308 clear: If true, clear the logcat.
309 dump: If true, dump the current logcat contents.
310 filter_specs: If set, a list of specs to filter the logcat.
311 logcat_format: If set, the format in which the logcat should be output.
312 Options include "brief", "process", "tag", "thread", "raw", "time",
313 "threadtime", and "long"
314 ring_buffer: If set, a list of alternate ring buffers to request.
315 Options include "main", "system", "radio", "events", "crash" or "all".
316 The default is equivalent to ["main", "system", "crash"].
317 timeout: (optional) If set, timeout per try in seconds. If clear or dump
318 is set, defaults to _DEFAULT_TIMEOUT.
319 retries: (optional) If clear or dump is set, the number of retries to
320 attempt. Otherwise, does nothing.
323 logcat output line by line.
334 cmd
.extend(['-v', logcat_format
])
336 for buffer_name
in ring_buffer
:
337 cmd
.extend(['-b', buffer_name
])
339 cmd
.extend(filter_specs
)
342 return self
._IterRunDeviceAdbCmd
(cmd
, timeout
)
344 timeout
= timeout
if timeout
is not None else _DEFAULT_TIMEOUT
345 return self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
).splitlines()
347 def Forward(self
, local
, remote
, timeout
=_DEFAULT_TIMEOUT
,
348 retries
=_DEFAULT_RETRIES
):
349 """Forward socket connections from the local socket to the remote socket.
351 Sockets are specified by one of:
353 localabstract:<unix domain socket name>
354 localreserved:<unix domain socket name>
355 localfilesystem:<unix domain socket name>
356 dev:<character device name>
357 jdwp:<process pid> (remote only)
360 local: The host socket.
361 remote: The device socket.
362 timeout: (optional) Timeout per try in seconds.
363 retries: (optional) Number of retries to attempt.
365 self
._RunDeviceAdbCmd
(['forward', str(local
), str(remote
)], timeout
,
368 def JDWP(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
369 """List of PIDs of processes hosting a JDWP transport.
372 timeout: (optional) Timeout per try in seconds.
373 retries: (optional) Number of retries to attempt.
376 A list of PIDs as strings.
378 return [a
.strip() for a
in
379 self
._RunDeviceAdbCmd
(['jdwp'], timeout
, retries
).split('\n')]
381 def Install(self
, apk_path
, forward_lock
=False, reinstall
=False,
382 sd_card
=False, timeout
=60*2, retries
=_DEFAULT_RETRIES
):
383 """Install an apk on the device.
386 apk_path: Host path to the APK file.
387 forward_lock: (optional) If set forward-locks the app.
388 reinstall: (optional) If set reinstalls the app, keeping its data.
389 sd_card: (optional) If set installs on the SD card.
390 timeout: (optional) Timeout per try in seconds.
391 retries: (optional) Number of retries to attempt.
393 _VerifyLocalFileExists(apk_path
)
402 output
= self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
403 if 'Success' not in output
:
404 raise device_errors
.AdbCommandFailedError(
405 cmd
, output
, device_serial
=self
._device
_serial
)
407 def Uninstall(self
, package
, keep_data
=False, timeout
=_DEFAULT_TIMEOUT
,
408 retries
=_DEFAULT_RETRIES
):
409 """Remove the app |package| from the device.
412 package: The package to uninstall.
413 keep_data: (optional) If set keep the data and cache directories.
414 timeout: (optional) Timeout per try in seconds.
415 retries: (optional) Number of retries to attempt.
421 output
= self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
422 if 'Failure' in output
:
423 raise device_errors
.AdbCommandFailedError(
424 cmd
, output
, device_serial
=self
._device
_serial
)
426 def Backup(self
, path
, packages
=None, apk
=False, shared
=False,
427 nosystem
=True, include_all
=False, timeout
=_DEFAULT_TIMEOUT
,
428 retries
=_DEFAULT_RETRIES
):
429 """Write an archive of the device's data to |path|.
432 path: Local path to store the backup file.
433 packages: List of to packages to be backed up.
434 apk: (optional) If set include the .apk files in the archive.
435 shared: (optional) If set buckup the device's SD card.
436 nosystem: (optional) If set exclude system applications.
437 include_all: (optional) If set back up all installed applications and
438 |packages| is optional.
439 timeout: (optional) Timeout per try in seconds.
440 retries: (optional) Number of retries to attempt.
442 cmd
= ['backup', path
]
446 cmd
.append('-shared')
448 cmd
.append('-nosystem')
453 assert bool(packages
) ^
bool(include_all
), (
454 'Provide \'packages\' or set \'include_all\' but not both.')
455 ret
= self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
456 _VerifyLocalFileExists(path
)
459 def Restore(self
, path
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
460 """Restore device contents from the backup archive.
463 path: Host path to the backup archive.
464 timeout: (optional) Timeout per try in seconds.
465 retries: (optional) Number of retries to attempt.
467 _VerifyLocalFileExists(path
)
468 self
._RunDeviceAdbCmd
(['restore'] + [path
], timeout
, retries
)
470 def WaitForDevice(self
, timeout
=60*5, retries
=_DEFAULT_RETRIES
):
471 """Block until the device is online.
474 timeout: (optional) Timeout per try in seconds.
475 retries: (optional) Number of retries to attempt.
477 self
._RunDeviceAdbCmd
(['wait-for-device'], timeout
, retries
)
479 def GetState(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
483 timeout: (optional) Timeout per try in seconds.
484 retries: (optional) Number of retries to attempt.
487 One of 'offline', 'bootloader', or 'device'.
489 return self
._RunDeviceAdbCmd
(['get-state'], timeout
, retries
).strip()
491 def GetDevPath(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
492 """Gets the device path.
495 timeout: (optional) Timeout per try in seconds.
496 retries: (optional) Number of retries to attempt.
499 The device path (e.g. usb:3-4)
501 return self
._RunDeviceAdbCmd
(['get-devpath'], timeout
, retries
)
503 def Remount(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
504 """Remounts the /system partition on the device read-write."""
505 self
._RunDeviceAdbCmd
(['remount'], timeout
, retries
)
507 def Reboot(self
, to_bootloader
=False, timeout
=60*5,
508 retries
=_DEFAULT_RETRIES
):
509 """Reboots the device.
512 to_bootloader: (optional) If set reboots to the bootloader.
513 timeout: (optional) Timeout per try in seconds.
514 retries: (optional) Number of retries to attempt.
517 cmd
= ['reboot-bootloader']
520 self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
522 def Root(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
523 """Restarts the adbd daemon with root permissions, if possible.
526 timeout: (optional) Timeout per try in seconds.
527 retries: (optional) Number of retries to attempt.
529 output
= self
._RunDeviceAdbCmd
(['root'], timeout
, retries
)
530 if 'cannot' in output
:
531 raise device_errors
.AdbCommandFailedError(
532 ['root'], output
, device_serial
=self
._device
_serial
)