• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4
5"""This module wraps Android's adb tool.
6
7This is a thin wrapper around the adb interface. Any additional complexity
8should be delegated to a higher level (ex. DeviceUtils).
9"""
10
11import collections
12# pylint: disable=import-error
13# pylint: disable=no-name-in-module
14import distutils.version as du_version
15import errno
16import logging
17import os
18import posixpath
19import re
20import subprocess
21
22from devil import base_error
23from devil import devil_env
24from devil.android import decorators
25from devil.android import device_errors
26from devil.utils import cmd_helper
27from devil.utils import lazy
28from devil.utils import timeout_retry
29
30with devil_env.SysPath(devil_env.DEPENDENCY_MANAGER_PATH):
31  import dependency_manager  # pylint: disable=import-error
32
33logger = logging.getLogger(__name__)
34
35
36ADB_KEYS_FILE = '/data/misc/adb/adb_keys'
37
38DEFAULT_TIMEOUT = 30
39DEFAULT_RETRIES = 2
40
41_ADB_VERSION_RE = re.compile(r'Android Debug Bridge version (\d+\.\d+\.\d+)')
42_EMULATOR_RE = re.compile(r'^emulator-[0-9]+$')
43_DEVICE_NOT_FOUND_RE = re.compile(r"error: device '(?P<serial>.+)' not found")
44_READY_STATE = 'device'
45_VERITY_DISABLE_RE = re.compile(r'(V|v)erity (is )?(already )?disabled'
46                                r'|Successfully disabled verity')
47_VERITY_ENABLE_RE = re.compile(r'(V|v)erity (is )?(already )?enabled'
48                               r'|Successfully enabled verity')
49_WAITING_FOR_DEVICE_RE = re.compile(r'- waiting for device -')
50
51
52def VerifyLocalFileExists(path):
53  """Verifies a local file exists.
54
55  Args:
56    path: Path to the local file.
57
58  Raises:
59    IOError: If the file doesn't exist.
60  """
61  if not os.path.exists(path):
62    raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), path)
63
64
65def _CreateAdbEnvironment():
66  adb_env = dict(os.environ)
67  adb_env['ADB_LIBUSB'] = '0'
68  return adb_env
69
70
71def _FindAdb():
72  try:
73    return devil_env.config.LocalPath('adb')
74  except dependency_manager.NoPathFoundError:
75    pass
76
77  try:
78    return os.path.join(devil_env.config.LocalPath('android_sdk'),
79                        'platform-tools', 'adb')
80  except dependency_manager.NoPathFoundError:
81    pass
82
83  try:
84    return devil_env.config.FetchPath('adb')
85  except dependency_manager.NoPathFoundError:
86    raise device_errors.NoAdbError()
87
88
89def _GetVersion():
90  # pylint: disable=protected-access
91  raw_version = AdbWrapper._RunAdbCmd(['version'], timeout=2, retries=0)
92  for l in raw_version.splitlines():
93    m = _ADB_VERSION_RE.search(l)
94    if m:
95      return m.group(1)
96  return None
97
98
99def _ShouldRetryAdbCmd(exc):
100  # Errors are potentially transient and should be retried, with the exception
101  # of NoAdbError. Exceptions [e.g. generated from SIGTERM handler] should be
102  # raised.
103  return (isinstance(exc, base_error.BaseError) and
104          not isinstance(exc, device_errors.NoAdbError))
105
106
107DeviceStat = collections.namedtuple('DeviceStat',
108                                    ['st_mode', 'st_size', 'st_time'])
109
110
111def _IsExtraneousLine(line, send_cmd):
112  """Determine if a line read from stdout in persistent shell is extraneous.
113
114  The results output to stdout by the persistent shell process
115  (in PersistentShell below) often include "extraneous" lines that are
116  not part of the output of the shell command. These "extraneous" lines
117  do not always appear and are of two forms: shell prompt lines and lines
118  that just duplicate what the input command was. This function
119  detects these extraneous lines. Since all these lines have the
120  original command in them, that is what it detects ror.
121
122  Args:
123      line: Output line to check.
124      send_cmd: Command that was sent to adb persistent shell.
125  """
126  return send_cmd.rstrip() in line
127
128
129class AdbWrapper(object):
130  """A wrapper around a local Android Debug Bridge executable."""
131
132  _ADB_ENV = _CreateAdbEnvironment()
133
134  _adb_path = lazy.WeakConstant(_FindAdb)
135  _adb_version = lazy.WeakConstant(_GetVersion)
136
137  def __init__(self, device_serial):
138    """Initializes the AdbWrapper.
139
140    Args:
141      device_serial: The device serial number as a string.
142    """
143    if not device_serial:
144      raise ValueError('A device serial must be specified')
145    self._device_serial = str(device_serial)
146
147  class PersistentShell(object):
148    '''Class to use persistent shell for ADB.
149
150    This class allows a persistent ADB shell to be created, where multiple
151    commands can be passed into it. This avoids the overhead of starting
152    up a new ADB shell for each command.
153
154    Example of use:
155    with PersistentShell('123456789') as pshell:
156        pshell.RunCommand('which ls')
157        pshell.RunCommand('echo TEST', close=True)
158    '''
159    def __init__(self, serial):
160      """Initialization function:
161
162      Args:
163        serial: Serial number of device.
164      """
165      self._cmd = [AdbWrapper.GetAdbPath(), '-s', serial, 'shell']
166      self._process = None
167
168    def __enter__(self):
169      self.Start()
170      self.WaitForReady()
171      return self
172
173    def __exit__(self, exc_type, exc_value, tb):
174      self.Stop()
175
176    def Start(self):
177      """Start the shell."""
178      if self._process is not None:
179        raise RuntimeError('Persistent shell already running.')
180      # pylint: disable=protected-access
181      self._process = subprocess.Popen(self._cmd,
182                                       stdin=subprocess.PIPE,
183                                       stdout=subprocess.PIPE,
184                                       shell=False,
185                                       env=AdbWrapper._ADB_ENV)
186
187    def WaitForReady(self):
188      """Wait for the shell to be ready after starting.
189
190      Sends an echo command, then waits until it gets a response.
191      """
192      self._process.stdin.write('echo\n')
193      output_line = self._process.stdout.readline()
194      while output_line.rstrip() != '':
195        output_line = self._process.stdout.readline()
196
197    def RunCommand(self, command, close=False):
198      """Runs an ADB command and returns the output.
199
200      Note that there can be approximately 40 ms of additional latency
201      between sending the command and receiving the results if close=False
202      due to the use of Nagle's algorithm in the TCP socket between the
203      adb server and client. To avoid this extra latency, set close=True.
204
205      Args:
206        command: Command to send.
207      Returns:
208        The command output, given as a list of lines, and the exit code
209      """
210
211      if close:
212        def run_cmd(cmd):
213          send_cmd = '( %s ); echo $?; exit;\n' % cmd.rstrip()
214          (output, _) = self._process.communicate(send_cmd)
215          self._process = None
216          for x in output.rstrip().splitlines():
217            yield x
218
219      else:
220        def run_cmd(cmd):
221          send_cmd = '( %s ); echo DONE:$?;\n' % cmd.rstrip()
222          self._process.stdin.write(send_cmd)
223          while True:
224            output_line = self._process.stdout.readline().rstrip()
225            if output_line[:5] == 'DONE:':
226              yield output_line[5:]
227              break
228            yield output_line
229
230      result = [line for line in run_cmd(command)
231                if not _IsExtraneousLine(line, command)]
232
233      return (result[:-1], int(result[-1]))
234
235    def Stop(self):
236      """Stops the ADB process if it is still running."""
237      if self._process is not None:
238        self._process.stdin.write('exit\n')
239        self._process = None
240
241  @classmethod
242  def GetAdbPath(cls):
243    return cls._adb_path.read()
244
245  @classmethod
246  def Version(cls):
247    return cls._adb_version.read()
248
249  @classmethod
250  def _BuildAdbCmd(cls, args, device_serial, cpu_affinity=None):
251    if cpu_affinity is not None:
252      cmd = ['taskset', '-c', str(cpu_affinity)]
253    else:
254      cmd = []
255    cmd.append(cls.GetAdbPath())
256    if device_serial is not None:
257      cmd.extend(['-s', device_serial])
258    cmd.extend(args)
259    return cmd
260
261  # pylint: disable=unused-argument
262  @classmethod
263  @decorators.WithTimeoutAndConditionalRetries(_ShouldRetryAdbCmd)
264  def _RunAdbCmd(cls, args, timeout=None, retries=None, device_serial=None,
265                 check_error=True, cpu_affinity=None,
266                 ensure_logs_on_timeout=False):
267    timeout = timeout_retry.CurrentTimeoutThreadGroup().GetRemainingTime()
268    if ensure_logs_on_timeout:
269      timeout = 0.95 * timeout
270    try:
271      status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
272          cls._BuildAdbCmd(args, device_serial, cpu_affinity=cpu_affinity),
273          timeout, env=cls._ADB_ENV)
274    except OSError as e:
275      if e.errno in (errno.ENOENT, errno.ENOEXEC):
276        raise device_errors.NoAdbError(msg=str(e))
277      else:
278        raise
279
280    # Best effort to catch errors from adb; unfortunately adb is very
281    # inconsistent with error reporting so many command failures present
282    # differently.
283    if status != 0 or (check_error and output.startswith('error:')):
284      not_found_m = _DEVICE_NOT_FOUND_RE.match(output)
285      device_waiting_m = _WAITING_FOR_DEVICE_RE.match(output)
286      if (device_waiting_m is not None
287          or (not_found_m is not None and
288              not_found_m.group('serial') == device_serial)):
289        raise device_errors.DeviceUnreachableError(device_serial)
290      else:
291        raise device_errors.AdbCommandFailedError(
292            args, output, status, device_serial)
293
294    return output
295  # pylint: enable=unused-argument
296
297  def _RunDeviceAdbCmd(
298      self, args, timeout, retries, check_error=True,
299      ensure_logs_on_timeout=False):
300    """Runs an adb command on the device associated with this object.
301
302    Args:
303      args: A list of arguments to adb.
304      timeout: Timeout in seconds.
305      retries: Number of retries.
306      check_error: Check that the command doesn't return an error message. This
307        does NOT check the exit status of shell commands.
308
309    Returns:
310      The output of the command.
311    """
312    return self._RunAdbCmd(args, timeout=timeout, retries=retries,
313                           device_serial=self._device_serial,
314                           check_error=check_error,
315                           ensure_logs_on_timeout=ensure_logs_on_timeout)
316
317  def _IterRunDeviceAdbCmd(self, args, iter_timeout, timeout):
318    """Runs an adb command and returns an iterator over its output lines.
319
320    Args:
321      args: A list of arguments to adb.
322      iter_timeout: Timeout for each iteration in seconds.
323      timeout: Timeout for the entire command in seconds.
324
325    Yields:
326      The output of the command line by line.
327    """
328    return cmd_helper.IterCmdOutputLines(
329        self._BuildAdbCmd(args, self._device_serial),
330        iter_timeout=iter_timeout,
331        timeout=timeout,
332        env=self._ADB_ENV)
333
334  def __eq__(self, other):
335    """Consider instances equal if they refer to the same device.
336
337    Args:
338      other: The instance to compare equality with.
339
340    Returns:
341      True if the instances are considered equal, false otherwise.
342    """
343    return self._device_serial == str(other)
344
345  def __str__(self):
346    """The string representation of an instance.
347
348    Returns:
349      The device serial number as a string.
350    """
351    return self._device_serial
352
353  def __repr__(self):
354    return '%s(\'%s\')' % (self.__class__.__name__, self)
355
356  # pylint: disable=unused-argument
357  @classmethod
358  def IsServerOnline(cls):
359    status, output = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb'])
360    output = [int(x) for x in output.split()]
361    logger.info('PIDs for adb found: %r', output)
362    return status == 0
363  # pylint: enable=unused-argument
364
365  @classmethod
366  def KillServer(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
367    cls._RunAdbCmd(['kill-server'], timeout=timeout, retries=retries)
368
369  @classmethod
370  def StartServer(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
371    # CPU affinity is used to reduce adb instability http://crbug.com/268450
372    cls._RunAdbCmd(['start-server'], timeout=timeout, retries=retries,
373                   cpu_affinity=0)
374
375  @classmethod
376  def GetDevices(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
377    """DEPRECATED. Refer to Devices(...) below."""
378    # TODO(jbudorick): Remove this function once no more clients are using it.
379    return cls.Devices(timeout=timeout, retries=retries)
380
381  @classmethod
382  def Devices(cls, desired_state=_READY_STATE, long_list=False,
383              timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
384    """Get the list of active attached devices.
385
386    Args:
387      desired_state: If not None, limit the devices returned to only those
388        in the given state.
389      long_list: Whether to use the long listing format.
390      timeout: (optional) Timeout per try in seconds.
391      retries: (optional) Number of retries to attempt.
392
393    Yields:
394      AdbWrapper instances.
395    """
396    lines = cls._RawDevices(long_list=long_list, timeout=timeout,
397                            retries=retries)
398    if long_list:
399      return [
400        [AdbWrapper(line[0])] + line[1:]
401        for line in lines
402        if (len(line) >= 2 and (not desired_state or line[1] == desired_state))
403      ]
404    else:
405      return [
406        AdbWrapper(line[0])
407        for line in lines
408        if (len(line) == 2 and (not desired_state or line[1] == desired_state))
409      ]
410
411  @classmethod
412  def _RawDevices(cls, long_list=False, timeout=DEFAULT_TIMEOUT,
413                  retries=DEFAULT_RETRIES):
414    cmd = ['devices']
415    if long_list:
416      cmd.append('-l')
417    output = cls._RunAdbCmd(cmd, timeout=timeout, retries=retries)
418    return [line.split() for line in output.splitlines()[1:]]
419
420  def GetDeviceSerial(self):
421    """Gets the device serial number associated with this object.
422
423    Returns:
424      Device serial number as a string.
425    """
426    return self._device_serial
427
428  def Push(self, local, remote, timeout=60 * 5, retries=DEFAULT_RETRIES):
429    """Pushes a file from the host to the device.
430
431    Args:
432      local: Path on the host filesystem.
433      remote: Path on the device filesystem.
434      timeout: (optional) Timeout per try in seconds.
435      retries: (optional) Number of retries to attempt.
436    """
437    VerifyLocalFileExists(local)
438
439    if (du_version.LooseVersion(self.Version()) <
440        du_version.LooseVersion('1.0.36')):
441
442      # Different versions of adb handle pushing a directory to an existing
443      # directory differently.
444
445      # In the version packaged with the M SDK, 1.0.32, the following push:
446      #   foo/bar -> /sdcard/foo/bar
447      # where bar is an existing directory both on the host and the device
448      # results in the contents of bar/ on the host being pushed to bar/ on
449      # the device, i.e.
450      #   foo/bar/A -> /sdcard/foo/bar/A
451      #   foo/bar/B -> /sdcard/foo/bar/B
452      #   ... etc.
453
454      # In the version packaged with the N SDK, 1.0.36, the same push under
455      # the same conditions results in a second bar/ directory being created
456      # underneath the first bar/ directory on the device, i.e.
457      #   foo/bar/A -> /sdcard/foo/bar/bar/A
458      #   foo/bar/B -> /sdcard/foo/bar/bar/B
459      #   ... etc.
460
461      # In order to provide a consistent interface to clients, we check whether
462      # the target is an existing directory on the device and, if so, modifies
463      # the target passed to adb to emulate the behavior on 1.0.36 and above.
464
465      # Note that this behavior may have started before 1.0.36; that's simply
466      # the earliest version we've confirmed thus far.
467
468      try:
469        self.Shell('test -d %s' % remote, timeout=timeout, retries=retries)
470        remote = posixpath.join(remote, posixpath.basename(local))
471      except device_errors.AdbShellCommandFailedError:
472        # The target directory doesn't exist on the device, so we can use it
473        # without modification.
474        pass
475
476    self._RunDeviceAdbCmd(['push', local, remote], timeout, retries)
477
478  def Pull(self, remote, local, timeout=60 * 5, retries=DEFAULT_RETRIES):
479    """Pulls a file from the device to the host.
480
481    Args:
482      remote: Path on the device filesystem.
483      local: Path on the host filesystem.
484      timeout: (optional) Timeout per try in seconds.
485      retries: (optional) Number of retries to attempt.
486    """
487    cmd = ['pull', remote, local]
488    self._RunDeviceAdbCmd(cmd, timeout, retries)
489    try:
490      VerifyLocalFileExists(local)
491    except IOError:
492      raise device_errors.AdbCommandFailedError(
493          cmd,
494          'File pulled from the device did not arrive on the host: %s' % local,
495          device_serial=str(self))
496
497  def StartShell(self, cmd):
498    """Starts a subprocess on the device and returns a handle to the process.
499
500    Args:
501      args: A sequence of program arguments. The executable to run is the first
502        item in the sequence.
503
504    Returns:
505      An instance of subprocess.Popen associated with the live process.
506    """
507    return cmd_helper.StartCmd(
508        self._BuildAdbCmd(['shell'] + cmd, self._device_serial))
509
510  def Shell(self, command, expect_status=0, ensure_logs_on_timeout=False,
511            timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
512    """Runs a shell command on the device.
513
514    Args:
515      command: A string with the shell command to run.
516      expect_status: (optional) Check that the command's exit status matches
517        this value. Default is 0. If set to None the test is skipped.
518      ensure_logs_on_timeout: If True, will use a timeout that is 5% smaller
519        than the remaining time on the thread watchdog for the internal adb
520        command, which allows to retrive logs on timeout.
521      timeout: (optional) Timeout per try in seconds.
522      retries: (optional) Number of retries to attempt.
523
524    Returns:
525      The output of the shell command as a string.
526
527    Raises:
528      device_errors.AdbCommandFailedError: If the exit status doesn't match
529        |expect_status|.
530    """
531    if expect_status is None:
532      args = ['shell', command]
533    else:
534      args = ['shell', '( %s );echo %%$?' % command.rstrip()]
535    output = self._RunDeviceAdbCmd(
536        args, timeout, retries, check_error=False,
537        ensure_logs_on_timeout=ensure_logs_on_timeout)
538    if expect_status is not None:
539      output_end = output.rfind('%')
540      if output_end < 0:
541        # causes the status string to become empty and raise a ValueError
542        output_end = len(output)
543
544      try:
545        status = int(output[output_end + 1:])
546      except ValueError:
547        logger.warning('exit status of shell command %r missing.', command)
548        raise device_errors.AdbShellCommandFailedError(
549            command, output, status=None, device_serial=self._device_serial)
550      output = output[:output_end]
551      if status != expect_status:
552        raise device_errors.AdbShellCommandFailedError(
553            command, output, status=status, device_serial=self._device_serial)
554    return output
555
556  def IterShell(self, command, timeout):
557    """Runs a shell command and returns an iterator over its output lines.
558
559    Args:
560      command: A string with the shell command to run.
561      timeout: Timeout in seconds.
562
563    Yields:
564      The output of the command line by line.
565    """
566    args = ['shell', command]
567    return cmd_helper.IterCmdOutputLines(
568      self._BuildAdbCmd(args, self._device_serial), timeout=timeout,
569      env=self._ADB_ENV)
570
571  def Ls(self, path, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
572    """List the contents of a directory on the device.
573
574    Args:
575      path: Path on the device filesystem.
576      timeout: (optional) Timeout per try in seconds.
577      retries: (optional) Number of retries to attempt.
578
579    Returns:
580      A list of pairs (filename, stat) for each file found in the directory,
581      where the stat object has the properties: st_mode, st_size, and st_time.
582
583    Raises:
584      AdbCommandFailedError if |path| does not specify a valid and accessible
585          directory in the device, or the output of "adb ls" command is less
586          than four columns
587    """
588    def ParseLine(line, cmd):
589      cols = line.split(None, 3)
590      if len(cols) < 4:
591        raise device_errors.AdbCommandFailedError(
592            cmd, line, "the output should be 4 columns, but is only %d columns"
593            % len(cols), device_serial=self._device_serial)
594      filename = cols.pop()
595      stat = DeviceStat(*[int(num, base=16) for num in cols])
596      return (filename, stat)
597
598    cmd = ['ls', path]
599    lines = self._RunDeviceAdbCmd(
600        cmd, timeout=timeout, retries=retries).splitlines()
601    if lines:
602      return [ParseLine(line, cmd) for line in lines]
603    else:
604      raise device_errors.AdbCommandFailedError(
605          cmd, 'path does not specify an accessible directory in the device',
606          device_serial=self._device_serial)
607
608  def Logcat(self, clear=False, dump=False, filter_specs=None,
609             logcat_format=None, ring_buffer=None, iter_timeout=None,
610             timeout=None, retries=DEFAULT_RETRIES):
611    """Get an iterable over the logcat output.
612
613    Args:
614      clear: If true, clear the logcat.
615      dump: If true, dump the current logcat contents.
616      filter_specs: If set, a list of specs to filter the logcat.
617      logcat_format: If set, the format in which the logcat should be output.
618        Options include "brief", "process", "tag", "thread", "raw", "time",
619        "threadtime", and "long"
620      ring_buffer: If set, a list of alternate ring buffers to request.
621        Options include "main", "system", "radio", "events", "crash" or "all".
622        The default is equivalent to ["main", "system", "crash"].
623      iter_timeout: If set and neither clear nor dump is set, the number of
624        seconds to wait between iterations. If no line is found before the
625        given number of seconds elapses, the iterable will yield None.
626      timeout: (optional) If set, timeout per try in seconds. If clear or dump
627        is set, defaults to DEFAULT_TIMEOUT.
628      retries: (optional) If clear or dump is set, the number of retries to
629        attempt. Otherwise, does nothing.
630
631    Yields:
632      logcat output line by line.
633    """
634    cmd = ['logcat']
635    use_iter = True
636    if clear:
637      cmd.append('-c')
638      use_iter = False
639    if dump:
640      cmd.append('-d')
641      use_iter = False
642    if logcat_format:
643      cmd.extend(['-v', logcat_format])
644    if ring_buffer:
645      for buffer_name in ring_buffer:
646        cmd.extend(['-b', buffer_name])
647    if filter_specs:
648      cmd.extend(filter_specs)
649
650    if use_iter:
651      return self._IterRunDeviceAdbCmd(cmd, iter_timeout, timeout)
652    else:
653      timeout = timeout if timeout is not None else DEFAULT_TIMEOUT
654      return self._RunDeviceAdbCmd(cmd, timeout, retries).splitlines()
655
656  def Forward(self, local, remote, allow_rebind=False,
657              timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
658    """Forward socket connections from the local socket to the remote socket.
659
660    Sockets are specified by one of:
661      tcp:<port>
662      localabstract:<unix domain socket name>
663      localreserved:<unix domain socket name>
664      localfilesystem:<unix domain socket name>
665      dev:<character device name>
666      jdwp:<process pid> (remote only)
667
668    Args:
669      local: The host socket.
670      remote: The device socket.
671      allow_rebind: A boolean indicating whether adb may rebind a local socket;
672        otherwise, the default, an exception is raised if the local socket is
673        already being forwarded.
674      timeout: (optional) Timeout per try in seconds.
675      retries: (optional) Number of retries to attempt.
676    """
677    cmd = ['forward']
678    if not allow_rebind:
679      cmd.append('--no-rebind')
680    cmd.extend([str(local), str(remote)])
681    output = self._RunDeviceAdbCmd(cmd, timeout, retries).strip()
682    if output:
683      logger.warning('Unexpected output from "adb forward": %s', output)
684
685  def ForwardRemove(self, local, timeout=DEFAULT_TIMEOUT,
686                    retries=DEFAULT_RETRIES):
687    """Remove a forward socket connection.
688
689    Args:
690      local: The host socket.
691      timeout: (optional) Timeout per try in seconds.
692      retries: (optional) Number of retries to attempt.
693    """
694    self._RunDeviceAdbCmd(['forward', '--remove', str(local)], timeout,
695                          retries)
696
697  def ForwardList(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
698    """List all currently forwarded socket connections.
699
700    Args:
701      timeout: (optional) Timeout per try in seconds.
702      retries: (optional) Number of retries to attempt.
703    Returns:
704      The output of adb forward --list as a string.
705    """
706    if (du_version.LooseVersion(self.Version()) >=
707        du_version.LooseVersion('1.0.36')):
708      # Starting in 1.0.36, this can occasionally fail with a protocol fault.
709      # As this interrupts all connections with all devices, we instead just
710      # return an empty list. This may give clients an inaccurate result, but
711      # that's usually better than crashing the adb server.
712
713      # TODO(jbudorick): Determine an appropriate upper version bound for this
714      # once b/31811775 is fixed.
715      return ''
716
717    return self._RunDeviceAdbCmd(['forward', '--list'], timeout, retries)
718
719  def JDWP(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
720    """List of PIDs of processes hosting a JDWP transport.
721
722    Args:
723      timeout: (optional) Timeout per try in seconds.
724      retries: (optional) Number of retries to attempt.
725
726    Returns:
727      A list of PIDs as strings.
728    """
729    return [a.strip() for a in
730            self._RunDeviceAdbCmd(['jdwp'], timeout, retries).split('\n')]
731
732  def Install(self, apk_path, forward_lock=False, allow_downgrade=False,
733              reinstall=False, sd_card=False, timeout=60 * 2,
734              retries=DEFAULT_RETRIES):
735    """Install an apk on the device.
736
737    Args:
738      apk_path: Host path to the APK file.
739      forward_lock: (optional) If set forward-locks the app.
740      allow_downgrade: (optional) If set, allows for downgrades.
741      reinstall: (optional) If set reinstalls the app, keeping its data.
742      sd_card: (optional) If set installs on the SD card.
743      timeout: (optional) Timeout per try in seconds.
744      retries: (optional) Number of retries to attempt.
745    """
746    VerifyLocalFileExists(apk_path)
747    cmd = ['install']
748    if forward_lock:
749      cmd.append('-l')
750    if reinstall:
751      cmd.append('-r')
752    if sd_card:
753      cmd.append('-s')
754    if allow_downgrade:
755      cmd.append('-d')
756    cmd.append(apk_path)
757    output = self._RunDeviceAdbCmd(cmd, timeout, retries)
758    if 'Success' not in output:
759      raise device_errors.AdbCommandFailedError(
760          cmd, output, device_serial=self._device_serial)
761
762  def InstallMultiple(self, apk_paths, forward_lock=False, reinstall=False,
763                      sd_card=False, allow_downgrade=False, partial=False,
764                      timeout=60 * 2, retries=DEFAULT_RETRIES):
765    """Install an apk with splits on the device.
766
767    Args:
768      apk_paths: Host path to the APK file.
769      forward_lock: (optional) If set forward-locks the app.
770      reinstall: (optional) If set reinstalls the app, keeping its data.
771      sd_card: (optional) If set installs on the SD card.
772      allow_downgrade: (optional) Allow versionCode downgrade.
773      partial: (optional) Package ID if apk_paths doesn't include all .apks.
774      timeout: (optional) Timeout per try in seconds.
775      retries: (optional) Number of retries to attempt.
776    """
777    for path in apk_paths:
778      VerifyLocalFileExists(path)
779    cmd = ['install-multiple']
780    if forward_lock:
781      cmd.append('-l')
782    if reinstall:
783      cmd.append('-r')
784    if sd_card:
785      cmd.append('-s')
786    if allow_downgrade:
787      cmd.append('-d')
788    if partial:
789      cmd.extend(('-p', partial))
790    cmd.extend(apk_paths)
791    output = self._RunDeviceAdbCmd(cmd, timeout, retries)
792    if 'Success' not in output:
793      raise device_errors.AdbCommandFailedError(
794          cmd, output, device_serial=self._device_serial)
795
796  def Uninstall(self, package, keep_data=False, timeout=DEFAULT_TIMEOUT,
797                retries=DEFAULT_RETRIES):
798    """Remove the app |package| from the device.
799
800    Args:
801      package: The package to uninstall.
802      keep_data: (optional) If set keep the data and cache directories.
803      timeout: (optional) Timeout per try in seconds.
804      retries: (optional) Number of retries to attempt.
805    """
806    cmd = ['uninstall']
807    if keep_data:
808      cmd.append('-k')
809    cmd.append(package)
810    output = self._RunDeviceAdbCmd(cmd, timeout, retries)
811    if 'Failure' in output or 'Exception' in output:
812      raise device_errors.AdbCommandFailedError(
813          cmd, output, device_serial=self._device_serial)
814
815  def Backup(self, path, packages=None, apk=False, shared=False,
816             nosystem=True, include_all=False, timeout=DEFAULT_TIMEOUT,
817             retries=DEFAULT_RETRIES):
818    """Write an archive of the device's data to |path|.
819
820    Args:
821      path: Local path to store the backup file.
822      packages: List of to packages to be backed up.
823      apk: (optional) If set include the .apk files in the archive.
824      shared: (optional) If set buckup the device's SD card.
825      nosystem: (optional) If set exclude system applications.
826      include_all: (optional) If set back up all installed applications and
827        |packages| is optional.
828      timeout: (optional) Timeout per try in seconds.
829      retries: (optional) Number of retries to attempt.
830    """
831    cmd = ['backup', '-f', path]
832    if apk:
833      cmd.append('-apk')
834    if shared:
835      cmd.append('-shared')
836    if nosystem:
837      cmd.append('-nosystem')
838    if include_all:
839      cmd.append('-all')
840    if packages:
841      cmd.extend(packages)
842    assert bool(packages) ^ bool(include_all), (
843        'Provide \'packages\' or set \'include_all\' but not both.')
844    ret = self._RunDeviceAdbCmd(cmd, timeout, retries)
845    VerifyLocalFileExists(path)
846    return ret
847
848  def Restore(self, path, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
849    """Restore device contents from the backup archive.
850
851    Args:
852      path: Host path to the backup archive.
853      timeout: (optional) Timeout per try in seconds.
854      retries: (optional) Number of retries to attempt.
855    """
856    VerifyLocalFileExists(path)
857    self._RunDeviceAdbCmd(['restore'] + [path], timeout, retries)
858
859  def WaitForDevice(self, timeout=60 * 5, retries=DEFAULT_RETRIES):
860    """Block until the device is online.
861
862    Args:
863      timeout: (optional) Timeout per try in seconds.
864      retries: (optional) Number of retries to attempt.
865    """
866    self._RunDeviceAdbCmd(['wait-for-device'], timeout, retries)
867
868  def GetState(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
869    """Get device state.
870
871    Args:
872      timeout: (optional) Timeout per try in seconds.
873      retries: (optional) Number of retries to attempt.
874
875    Returns:
876      One of 'offline', 'bootloader', or 'device'.
877    """
878    # TODO(jbudorick): Revert to using get-state once it doesn't cause a
879    # a protocol fault.
880    # return self._RunDeviceAdbCmd(['get-state'], timeout, retries).strip()
881
882    lines = self._RawDevices(timeout=timeout, retries=retries)
883    for line in lines:
884      if len(line) >= 2 and line[0] == self._device_serial:
885        return line[1]
886    return 'offline'
887
888  def GetDevPath(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
889    """Gets the device path.
890
891    Args:
892      timeout: (optional) Timeout per try in seconds.
893      retries: (optional) Number of retries to attempt.
894
895    Returns:
896      The device path (e.g. usb:3-4)
897    """
898    return self._RunDeviceAdbCmd(['get-devpath'], timeout, retries)
899
900  def Remount(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
901    """Remounts the /system partition on the device read-write."""
902    self._RunDeviceAdbCmd(['remount'], timeout, retries)
903
904  def Reboot(self, to_bootloader=False, timeout=60 * 5,
905             retries=DEFAULT_RETRIES):
906    """Reboots the device.
907
908    Args:
909      to_bootloader: (optional) If set reboots to the bootloader.
910      timeout: (optional) Timeout per try in seconds.
911      retries: (optional) Number of retries to attempt.
912    """
913    if to_bootloader:
914      cmd = ['reboot-bootloader']
915    else:
916      cmd = ['reboot']
917    self._RunDeviceAdbCmd(cmd, timeout, retries)
918
919  def Root(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
920    """Restarts the adbd daemon with root permissions, if possible.
921
922    Args:
923      timeout: (optional) Timeout per try in seconds.
924      retries: (optional) Number of retries to attempt.
925    """
926    output = self._RunDeviceAdbCmd(['root'], timeout, retries)
927    if 'cannot' in output:
928      raise device_errors.AdbCommandFailedError(
929          ['root'], output, device_serial=self._device_serial)
930
931  def Emu(self, cmd, timeout=DEFAULT_TIMEOUT,
932               retries=DEFAULT_RETRIES):
933    """Runs an emulator console command.
934
935    See http://developer.android.com/tools/devices/emulator.html#console
936
937    Args:
938      cmd: The command to run on the emulator console.
939      timeout: (optional) Timeout per try in seconds.
940      retries: (optional) Number of retries to attempt.
941
942    Returns:
943      The output of the emulator console command.
944    """
945    if isinstance(cmd, basestring):
946      cmd = [cmd]
947    return self._RunDeviceAdbCmd(['emu'] + cmd, timeout, retries)
948
949  def DisableVerity(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
950    """Disable Marshmallow's Verity security feature"""
951    output = self._RunDeviceAdbCmd(['disable-verity'], timeout, retries)
952    if output and not _VERITY_DISABLE_RE.search(output):
953      raise device_errors.AdbCommandFailedError(
954          ['disable-verity'], output, device_serial=self._device_serial)
955
956  def EnableVerity(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
957    """Enable Marshmallow's Verity security feature"""
958    output = self._RunDeviceAdbCmd(['enable-verity'], timeout, retries)
959    if output and not _VERITY_ENABLE_RE.search(output):
960      raise device_errors.AdbCommandFailedError(
961          ['enable-verity'], output, device_serial=self._device_serial)
962
963  @property
964  def is_emulator(self):
965    return _EMULATOR_RE.match(self._device_serial)
966
967  @property
968  def is_ready(self):
969    try:
970      return self.GetState() == _READY_STATE
971    except device_errors.CommandFailedError:
972      return False
973