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).
17 from pylib
import cmd_helper
18 from pylib
import constants
19 from pylib
.device
import decorators
20 from pylib
.device
import device_errors
21 from pylib
.utils
import timeout_retry
27 _EMULATOR_RE
= re
.compile(r
'^emulator-[0-9]+$')
29 _READY_STATE
= 'device'
32 def _VerifyLocalFileExists(path
):
33 """Verifies a local file exists.
36 path: Path to the local file.
39 IOError: If the file doesn't exist.
41 if not os
.path
.exists(path
):
42 raise IOError(errno
.ENOENT
, os
.strerror(errno
.ENOENT
), path
)
45 DeviceStat
= collections
.namedtuple('DeviceStat',
46 ['st_mode', 'st_size', 'st_time'])
49 class AdbWrapper(object):
50 """A wrapper around a local Android Debug Bridge executable."""
52 def __init__(self
, device_serial
):
53 """Initializes the AdbWrapper.
56 device_serial: The device serial number as a string.
59 raise ValueError('A device serial must be specified')
60 self
._device
_serial
= str(device_serial
)
62 # pylint: disable=unused-argument
64 def _BuildAdbCmd(cls
, args
, device_serial
, cpu_affinity
=None):
65 if cpu_affinity
is not None:
66 cmd
= ['taskset', '-c', str(cpu_affinity
)]
69 cmd
.append(constants
.GetAdbPath())
70 if device_serial
is not None:
71 cmd
.extend(['-s', device_serial
])
74 # pylint: enable=unused-argument
76 # pylint: disable=unused-argument
78 @decorators.WithTimeoutAndRetries
79 def _RunAdbCmd(cls
, args
, timeout
=None, retries
=None, device_serial
=None,
80 check_error
=True, cpu_affinity
=None):
81 status
, output
= cmd_helper
.GetCmdStatusAndOutputWithTimeout(
82 cls
._BuildAdbCmd
(args
, device_serial
, cpu_affinity
=cpu_affinity
),
83 timeout_retry
.CurrentTimeoutThread().GetRemainingTime())
85 raise device_errors
.AdbCommandFailedError(
86 args
, output
, status
, device_serial
)
87 # This catches some errors, including when the device drops offline;
88 # unfortunately adb is very inconsistent with error reporting so many
89 # command failures present differently.
90 if check_error
and output
.startswith('error:'):
91 raise device_errors
.AdbCommandFailedError(args
, output
)
93 # pylint: enable=unused-argument
95 def _RunDeviceAdbCmd(self
, args
, timeout
, retries
, check_error
=True):
96 """Runs an adb command on the device associated with this object.
99 args: A list of arguments to adb.
100 timeout: Timeout in seconds.
101 retries: Number of retries.
102 check_error: Check that the command doesn't return an error message. This
103 does NOT check the exit status of shell commands.
106 The output of the command.
108 return self
._RunAdbCmd
(args
, timeout
=timeout
, retries
=retries
,
109 device_serial
=self
._device
_serial
,
110 check_error
=check_error
)
112 def _IterRunDeviceAdbCmd(self
, args
, timeout
):
113 """Runs an adb command and returns an iterator over its output lines.
116 args: A list of arguments to adb.
117 timeout: Timeout in seconds.
120 The output of the command line by line.
122 return cmd_helper
.IterCmdOutputLines(
123 self
._BuildAdbCmd
(args
, self
._device
_serial
), timeout
=timeout
)
125 def __eq__(self
, other
):
126 """Consider instances equal if they refer to the same device.
129 other: The instance to compare equality with.
132 True if the instances are considered equal, false otherwise.
134 return self
._device
_serial
== str(other
)
137 """The string representation of an instance.
140 The device serial number as a string.
142 return self
._device
_serial
145 return '%s(\'%s\')' % (self
.__class
__.__name
__, self
)
147 # pylint: disable=unused-argument
149 def IsServerOnline(cls
):
150 status
, output
= cmd_helper
.GetCmdStatusAndOutput(['pgrep', 'adb'])
151 output
= [int(x
) for x
in output
.split()]
152 logging
.info('PIDs for adb found: %r', output
)
154 # pylint: enable=unused-argument
157 def KillServer(cls
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
158 cls
._RunAdbCmd
(['kill-server'], timeout
=timeout
, retries
=retries
)
161 def StartServer(cls
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
162 # CPU affinity is used to reduce adb instability http://crbug.com/268450
163 cls
._RunAdbCmd
(['start-server'], timeout
=timeout
, retries
=retries
,
167 def GetDevices(cls
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
168 """DEPRECATED. Refer to Devices(...) below."""
169 # TODO(jbudorick): Remove this function once no more clients are using it.
170 return cls
.Devices(timeout
=timeout
, retries
=retries
)
173 def Devices(cls
, is_ready
=True, timeout
=_DEFAULT_TIMEOUT
,
174 retries
=_DEFAULT_RETRIES
):
175 """Get the list of active attached devices.
178 is_ready: Whether the devices should be limited to only those that are
180 timeout: (optional) Timeout per try in seconds.
181 retries: (optional) Number of retries to attempt.
184 AdbWrapper instances.
186 output
= cls
._RunAdbCmd
(['devices'], timeout
=timeout
, retries
=retries
)
187 lines
= (line
.split() for line
in output
.splitlines())
188 return [AdbWrapper(line
[0]) for line
in lines
189 if len(line
) == 2 and (not is_ready
or line
[1] == _READY_STATE
)]
191 def GetDeviceSerial(self
):
192 """Gets the device serial number associated with this object.
195 Device serial number as a string.
197 return self
._device
_serial
199 def Push(self
, local
, remote
, timeout
=60*5, retries
=_DEFAULT_RETRIES
):
200 """Pushes a file from the host to the device.
203 local: Path on the host filesystem.
204 remote: Path on the device filesystem.
205 timeout: (optional) Timeout per try in seconds.
206 retries: (optional) Number of retries to attempt.
208 _VerifyLocalFileExists(local
)
209 self
._RunDeviceAdbCmd
(['push', local
, remote
], timeout
, retries
)
211 def Pull(self
, remote
, local
, timeout
=60*5, retries
=_DEFAULT_RETRIES
):
212 """Pulls a file from the device to the host.
215 remote: Path on the device filesystem.
216 local: Path on the host filesystem.
217 timeout: (optional) Timeout per try in seconds.
218 retries: (optional) Number of retries to attempt.
220 cmd
= ['pull', remote
, local
]
221 self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
223 _VerifyLocalFileExists(local
)
225 raise device_errors
.AdbCommandFailedError(
226 cmd
, 'File not found on host: %s' % local
, device_serial
=str(self
))
228 def Shell(self
, command
, expect_status
=0, timeout
=_DEFAULT_TIMEOUT
,
229 retries
=_DEFAULT_RETRIES
):
230 """Runs a shell command on the device.
233 command: A string with the shell command to run.
234 expect_status: (optional) Check that the command's exit status matches
235 this value. Default is 0. If set to None the test is skipped.
236 timeout: (optional) Timeout per try in seconds.
237 retries: (optional) Number of retries to attempt.
240 The output of the shell command as a string.
243 device_errors.AdbCommandFailedError: If the exit status doesn't match
246 if expect_status
is None:
247 args
= ['shell', command
]
249 args
= ['shell', '%s; echo %%$?;' % command
.rstrip()]
250 output
= self
._RunDeviceAdbCmd
(args
, timeout
, retries
, check_error
=False)
251 if expect_status
is not None:
252 output_end
= output
.rfind('%')
254 # causes the status string to become empty and raise a ValueError
255 output_end
= len(output
)
258 status
= int(output
[output_end
+1:])
260 logging
.warning('exit status of shell command %r missing.', command
)
261 raise device_errors
.AdbShellCommandFailedError(
262 command
, output
, status
=None, device_serial
=self
._device
_serial
)
263 output
= output
[:output_end
]
264 if status
!= expect_status
:
265 raise device_errors
.AdbShellCommandFailedError(
266 command
, output
, status
=status
, device_serial
=self
._device
_serial
)
269 def IterShell(self
, command
, timeout
):
270 """Runs a shell command and returns an iterator over its output lines.
273 command: A string with the shell command to run.
274 timeout: Timeout in seconds.
277 The output of the command line by line.
279 args
= ['shell', command
]
280 return cmd_helper
.IterCmdOutputLines(
281 self
._BuildAdbCmd
(args
, self
._device
_serial
), timeout
=timeout
)
283 def Ls(self
, path
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
284 """List the contents of a directory on the device.
287 path: Path on the device filesystem.
288 timeout: (optional) Timeout per try in seconds.
289 retries: (optional) Number of retries to attempt.
292 A list of pairs (filename, stat) for each file found in the directory,
293 where the stat object has the properties: st_mode, st_size, and st_time.
296 AdbCommandFailedError if |path| does not specify a valid and accessible
297 directory in the device.
300 cols
= line
.split(None, 3)
301 filename
= cols
.pop()
302 stat
= DeviceStat(*[int(num
, base
=16) for num
in cols
])
303 return (filename
, stat
)
306 lines
= self
._RunDeviceAdbCmd
(
307 cmd
, timeout
=timeout
, retries
=retries
).splitlines()
309 return [ParseLine(line
) for line
in lines
]
311 raise device_errors
.AdbCommandFailedError(
312 cmd
, 'path does not specify an accessible directory in the device',
313 device_serial
=self
._device
_serial
)
315 def Logcat(self
, clear
=False, dump
=False, filter_specs
=None,
316 logcat_format
=None, ring_buffer
=None, timeout
=None,
317 retries
=_DEFAULT_RETRIES
):
318 """Get an iterable over the logcat output.
321 clear: If true, clear the logcat.
322 dump: If true, dump the current logcat contents.
323 filter_specs: If set, a list of specs to filter the logcat.
324 logcat_format: If set, the format in which the logcat should be output.
325 Options include "brief", "process", "tag", "thread", "raw", "time",
326 "threadtime", and "long"
327 ring_buffer: If set, a list of alternate ring buffers to request.
328 Options include "main", "system", "radio", "events", "crash" or "all".
329 The default is equivalent to ["main", "system", "crash"].
330 timeout: (optional) If set, timeout per try in seconds. If clear or dump
331 is set, defaults to _DEFAULT_TIMEOUT.
332 retries: (optional) If clear or dump is set, the number of retries to
333 attempt. Otherwise, does nothing.
336 logcat output line by line.
347 cmd
.extend(['-v', logcat_format
])
349 for buffer_name
in ring_buffer
:
350 cmd
.extend(['-b', buffer_name
])
352 cmd
.extend(filter_specs
)
355 return self
._IterRunDeviceAdbCmd
(cmd
, timeout
)
357 timeout
= timeout
if timeout
is not None else _DEFAULT_TIMEOUT
358 return self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
).splitlines()
360 def Forward(self
, local
, remote
, timeout
=_DEFAULT_TIMEOUT
,
361 retries
=_DEFAULT_RETRIES
):
362 """Forward socket connections from the local socket to the remote socket.
364 Sockets are specified by one of:
366 localabstract:<unix domain socket name>
367 localreserved:<unix domain socket name>
368 localfilesystem:<unix domain socket name>
369 dev:<character device name>
370 jdwp:<process pid> (remote only)
373 local: The host socket.
374 remote: The device socket.
375 timeout: (optional) Timeout per try in seconds.
376 retries: (optional) Number of retries to attempt.
378 self
._RunDeviceAdbCmd
(['forward', str(local
), str(remote
)], timeout
,
381 def JDWP(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
382 """List of PIDs of processes hosting a JDWP transport.
385 timeout: (optional) Timeout per try in seconds.
386 retries: (optional) Number of retries to attempt.
389 A list of PIDs as strings.
391 return [a
.strip() for a
in
392 self
._RunDeviceAdbCmd
(['jdwp'], timeout
, retries
).split('\n')]
394 def Install(self
, apk_path
, forward_lock
=False, reinstall
=False,
395 sd_card
=False, timeout
=60*2, retries
=_DEFAULT_RETRIES
):
396 """Install an apk on the device.
399 apk_path: Host path to the APK file.
400 forward_lock: (optional) If set forward-locks the app.
401 reinstall: (optional) If set reinstalls the app, keeping its data.
402 sd_card: (optional) If set installs on the SD card.
403 timeout: (optional) Timeout per try in seconds.
404 retries: (optional) Number of retries to attempt.
406 _VerifyLocalFileExists(apk_path
)
415 output
= self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
416 if 'Success' not in output
:
417 raise device_errors
.AdbCommandFailedError(
418 cmd
, output
, device_serial
=self
._device
_serial
)
420 def InstallMultiple(self
, apk_paths
, forward_lock
=False, reinstall
=False,
421 sd_card
=False, allow_downgrade
=False, partial
=False,
422 timeout
=60*2, retries
=_DEFAULT_RETRIES
):
423 """Install an apk with splits on the device.
426 apk_paths: Host path to the APK file.
427 forward_lock: (optional) If set forward-locks the app.
428 reinstall: (optional) If set reinstalls the app, keeping its data.
429 sd_card: (optional) If set installs on the SD card.
430 timeout: (optional) Timeout per try in seconds.
431 retries: (optional) Number of retries to attempt.
432 allow_downgrade: (optional) Allow versionCode downgrade.
433 partial: (optional) Package ID if apk_paths doesn't include all .apks.
435 for path
in apk_paths
:
436 _VerifyLocalFileExists(path
)
437 cmd
= ['install-multiple']
447 cmd
.extend(('-p', partial
))
448 cmd
.extend(apk_paths
)
449 output
= self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
450 if 'Success' not in output
:
451 raise device_errors
.AdbCommandFailedError(
452 cmd
, output
, device_serial
=self
._device
_serial
)
454 def Uninstall(self
, package
, keep_data
=False, timeout
=_DEFAULT_TIMEOUT
,
455 retries
=_DEFAULT_RETRIES
):
456 """Remove the app |package| from the device.
459 package: The package to uninstall.
460 keep_data: (optional) If set keep the data and cache directories.
461 timeout: (optional) Timeout per try in seconds.
462 retries: (optional) Number of retries to attempt.
468 output
= self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
469 if 'Failure' in output
:
470 raise device_errors
.AdbCommandFailedError(
471 cmd
, output
, device_serial
=self
._device
_serial
)
473 def Backup(self
, path
, packages
=None, apk
=False, shared
=False,
474 nosystem
=True, include_all
=False, timeout
=_DEFAULT_TIMEOUT
,
475 retries
=_DEFAULT_RETRIES
):
476 """Write an archive of the device's data to |path|.
479 path: Local path to store the backup file.
480 packages: List of to packages to be backed up.
481 apk: (optional) If set include the .apk files in the archive.
482 shared: (optional) If set buckup the device's SD card.
483 nosystem: (optional) If set exclude system applications.
484 include_all: (optional) If set back up all installed applications and
485 |packages| is optional.
486 timeout: (optional) Timeout per try in seconds.
487 retries: (optional) Number of retries to attempt.
489 cmd
= ['backup', '-f', path
]
493 cmd
.append('-shared')
495 cmd
.append('-nosystem')
500 assert bool(packages
) ^
bool(include_all
), (
501 'Provide \'packages\' or set \'include_all\' but not both.')
502 ret
= self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
503 _VerifyLocalFileExists(path
)
506 def Restore(self
, path
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
507 """Restore device contents from the backup archive.
510 path: Host path to the backup archive.
511 timeout: (optional) Timeout per try in seconds.
512 retries: (optional) Number of retries to attempt.
514 _VerifyLocalFileExists(path
)
515 self
._RunDeviceAdbCmd
(['restore'] + [path
], timeout
, retries
)
517 def WaitForDevice(self
, timeout
=60*5, retries
=_DEFAULT_RETRIES
):
518 """Block until the device is online.
521 timeout: (optional) Timeout per try in seconds.
522 retries: (optional) Number of retries to attempt.
524 self
._RunDeviceAdbCmd
(['wait-for-device'], timeout
, retries
)
526 def GetState(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
530 timeout: (optional) Timeout per try in seconds.
531 retries: (optional) Number of retries to attempt.
534 One of 'offline', 'bootloader', or 'device'.
536 return self
._RunDeviceAdbCmd
(['get-state'], timeout
, retries
).strip()
538 def GetDevPath(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
539 """Gets the device path.
542 timeout: (optional) Timeout per try in seconds.
543 retries: (optional) Number of retries to attempt.
546 The device path (e.g. usb:3-4)
548 return self
._RunDeviceAdbCmd
(['get-devpath'], timeout
, retries
)
550 def Remount(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
551 """Remounts the /system partition on the device read-write."""
552 self
._RunDeviceAdbCmd
(['remount'], timeout
, retries
)
554 def Reboot(self
, to_bootloader
=False, timeout
=60*5,
555 retries
=_DEFAULT_RETRIES
):
556 """Reboots the device.
559 to_bootloader: (optional) If set reboots to the bootloader.
560 timeout: (optional) Timeout per try in seconds.
561 retries: (optional) Number of retries to attempt.
564 cmd
= ['reboot-bootloader']
567 self
._RunDeviceAdbCmd
(cmd
, timeout
, retries
)
569 def Root(self
, timeout
=_DEFAULT_TIMEOUT
, retries
=_DEFAULT_RETRIES
):
570 """Restarts the adbd daemon with root permissions, if possible.
573 timeout: (optional) Timeout per try in seconds.
574 retries: (optional) Number of retries to attempt.
576 output
= self
._RunDeviceAdbCmd
(['root'], timeout
, retries
)
577 if 'cannot' in output
:
578 raise device_errors
.AdbCommandFailedError(
579 ['root'], output
, device_serial
=self
._device
_serial
)
581 def Emu(self
, cmd
, timeout
=_DEFAULT_TIMEOUT
,
582 retries
=_DEFAULT_RETRIES
):
583 """Runs an emulator console command.
585 See http://developer.android.com/tools/devices/emulator.html#console
588 cmd: The command to run on the emulator console.
589 timeout: (optional) Timeout per try in seconds.
590 retries: (optional) Number of retries to attempt.
593 The output of the emulator console command.
595 if isinstance(cmd
, basestring
):
597 return self
._RunDeviceAdbCmd
(['emu'] + cmd
, timeout
, retries
)
600 def is_emulator(self
):
601 return _EMULATOR_RE
.match(self
._device
_serial
)
606 return self
.GetState() == _READY_STATE
607 except device_errors
.CommandFailedError
: