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