Beispiel #1
0
 def testInitialized(self):
     """Ensure that reading doesn't reinitialize the value."""
     initializer = mock.Mock(return_value='initializer called')
     test_constant = lazy.WeakConstant(initializer)
     test_constant._initialized.set()
     test_constant._val = 'initializer not called'
     self.assertEquals('initializer not called', test_constant.read())
     self.assertFalse(initializer.mock_calls)  # assert not called
 def testUninitialized(self):
   """Ensure that the first read calls the initializer."""
   initializer = mock.Mock(return_value='initializer called')
   test_constant = lazy.WeakConstant(initializer)
   self.assertEquals(
       'initializer called',
       test_constant.read())
   initializer.assert_called_once()
Beispiel #3
0
    def testFirstCallHangs(self):
        """Ensure that reading works even if the first initializer call hangs."""
        dyn = DynamicSideEffect(
            [lambda: time.sleep(10), lambda: 'second try worked!'])

        initializer = mock.Mock(side_effect=dyn)
        test_constant = lazy.WeakConstant(initializer)
        self.assertEquals('second try worked!',
                          timeout_retry.Run(test_constant.read, 1, 1))
        initializer.assert_has_calls([mock.call(), mock.call()])
Beispiel #4
0
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This module wraps Android's split-select tool."""

from devil.android.sdk import build_tools
from devil.utils import cmd_helper
from devil.utils import lazy

_split_select_path = lazy.WeakConstant(
    lambda: build_tools.GetPath('split-select'))


def _RunSplitSelectCmd(args):
    """Runs a split-select command.

  Args:
    args: A list of arguments for split-select.

  Returns:
    The output of the command.
  """
    cmd = [_split_select_path.read()] + args
    status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
    if status != 0:
        raise Exception('Failed running command "%s" with output "%s".' %
                        (' '.join(cmd), output))
    return output


def _SplitConfig(device, allow_cached_props=False):
Beispiel #5
0
import posixpath
import re
import sys
import tempfile
import zipfile
import zlib

import devil_chromium
from devil.android.sdk import build_tools
from devil.utils import cmd_helper
from devil.utils import lazy
import method_count
from pylib import constants
from pylib.constants import host_paths

_AAPT_PATH = lazy.WeakConstant(lambda: build_tools.GetPath('aapt'))
_BUILD_UTILS_PATH = os.path.join(host_paths.DIR_SOURCE_ROOT, 'build',
                                 'android', 'gyp')

with host_paths.SysPath(os.path.join(host_paths.DIR_SOURCE_ROOT, 'build')):
    import gn_helpers  # pylint: disable=import-error

with host_paths.SysPath(host_paths.BUILD_COMMON_PATH):
    import perf_tests_results_helper  # pylint: disable=import-error

with host_paths.SysPath(host_paths.TRACING_PATH):
    from tracing.value import convert_chart_json  # pylint: disable=import-error

with host_paths.SysPath(_BUILD_UTILS_PATH, 0):
    from util import build_utils  # pylint: disable=import-error
    from util import zipalign  # pylint: disable=import-error
Beispiel #6
0
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This module wraps bundletool."""

import json

from devil import base_error
from devil import devil_env
from devil.utils import cmd_helper
from devil.utils import lazy

with devil_env.SysPath(devil_env.PY_UTILS_PATH):
    from py_utils import tempfile_ext

_bundletool_path = lazy.WeakConstant(
    lambda: devil_env.config.FetchPath('bundletool'))


def ExtractApks(output_dir,
                apks_path,
                abis,
                locales,
                features,
                pixel_density,
                sdk_version,
                modules=None):
    """Extracts splits from APKS archive.

  Args:
    output_dir: Directory to extract splits into.
    apks_path: Path to APKS archive.
Beispiel #7
0
class Fastboot(object):

    _fastboot_path = lazy.WeakConstant(
        lambda: devil_env.config.FetchPath('fastboot'))

    def __init__(self,
                 device_serial,
                 default_timeout=_DEFAULT_TIMEOUT,
                 default_retries=_DEFAULT_RETRIES):
        """Initializes the FastbootWrapper.

    Args:
      device_serial: The device serial number as a string.
    """
        if not device_serial:
            raise ValueError('A device serial must be specified')
        self._device_serial = str(device_serial)
        self._default_timeout = default_timeout
        self._default_retries = default_retries

    def __str__(self):
        return self._device_serial

    @classmethod
    def _RunFastbootCommand(cls, cmd):
        """Run a generic fastboot command.

    Args:
      cmd: Command to run. Must be list of args, the first one being the command

    Returns:
      output of command.

    Raises:
      TypeError: If cmd is not of type list.
    """
        if isinstance(cmd, list):
            cmd = [cls._fastboot_path.read()] + cmd
        else:
            raise TypeError(
                'Command for _RunDeviceFastbootCommand must be a list.')
        # fastboot can't be trusted to keep non-error output out of stderr, so
        # capture stderr as part of stdout.
        status, output = cmd_helper.GetCmdStatusAndOutput(cmd,
                                                          merge_stderr=True)
        if int(status) != 0:
            raise device_errors.FastbootCommandFailedError(cmd, output, status)
        return output

    def _RunDeviceFastbootCommand(self, cmd):
        """Run a fastboot command on the device associated with this object.

    Args:
      cmd: Command to run. Must be list of args, the first one being the command

    Returns:
      output of command.

    Raises:
      TypeError: If cmd is not of type list.
    """
        if isinstance(cmd, list):
            cmd = ['-s', self._device_serial] + cmd
        return self._RunFastbootCommand(cmd)

    @decorators.WithTimeoutAndRetriesDefaults(_DEFAULT_TIMEOUT,
                                              _DEFAULT_RETRIES)
    def GetVar(self, variable, timeout=None, retries=None):
        args = ['getvar', variable]
        output = self._RunDeviceFastbootCommand(args)
        # getvar returns timing information on the last line of output, so only
        # parse the first line.
        output = output.splitlines()[0]
        # And the first line should match the format '$(var): $(value)'.
        if variable + ': ' not in output:
            raise device_errors.FastbootCommandFailedError(
                args, output, message="Unknown 'getvar' output format.")
        return output.split('%s: ' % variable)[1].strip()

    @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0)
    def Flash(self, partition, image, timeout=None, retries=None):
        """Flash partition with img.

    Args:
      partition: Partition to be flashed.
      image: location of image to flash with.
    """
        self._RunDeviceFastbootCommand(['flash', partition, image])

    @classmethod
    @decorators.WithTimeoutAndRetriesDefaults(_DEFAULT_TIMEOUT,
                                              _DEFAULT_RETRIES)
    def Devices(cls, timeout=None, retries=None):
        """Outputs list of devices in fastboot mode.

    Returns:
      List of Fastboot objects, one for each device in fastboot.
    """
        output = cls._RunFastbootCommand(['devices'])
        return [Fastboot(line.split()[0]) for line in output.splitlines()]

    @decorators.WithTimeoutAndRetriesFromInstance()
    def RebootBootloader(self, timeout=None, retries=None):
        """Reboot from fastboot, into fastboot."""
        self._RunDeviceFastbootCommand(['reboot-bootloader'])

    @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0)
    def Reboot(self, timeout=None, retries=None):
        """Reboot from fastboot to normal usage"""
        self._RunDeviceFastbootCommand(['reboot'])

    @decorators.WithTimeoutAndRetriesFromInstance()
    def SetOemOffModeCharge(self, value, timeout=None, retries=None):
        """Sets off mode charging

    Args:
      value: boolean value to set off-mode-charging on or off.
    """
        self._RunDeviceFastbootCommand(
            ['oem', 'off-mode-charge',
             str(int(value))])
Beispiel #8
0
class AdbWrapper(object):
    """A wrapper around a local Android Debug Bridge executable."""

    _adb_path = lazy.WeakConstant(_FindAdb)
    _adb_version = lazy.WeakConstant(_GetVersion)

    def __init__(self, device_serial):
        """Initializes the AdbWrapper.

    Args:
      device_serial: The device serial number as a string.
    """
        if not device_serial:
            raise ValueError('A device serial must be specified')
        self._device_serial = str(device_serial)

    class PersistentShell(object):
        '''Class to use persistent shell for ADB.

    This class allows a persistent ADB shell to be created, where multiple
    commands can be passed into it. This avoids the overhead of starting
    up a new ADB shell for each command.

    Example of use:
    with pshell as PersistentShell('123456789'):
        pshell.RunCommand('which ls')
        pshell.RunCommandAndClose('echo TEST')
    '''
        def __init__(self, serial):
            """Initialization function:

      Args:
        serial: Serial number of device.
      """
            self._cmd = [AdbWrapper.GetAdbPath(), '-s', serial, 'shell']
            self._process = None

        def __enter__(self):
            self.Start()
            self.WaitForReady()
            return self

        def __exit__(self, exc_type, exc_value, tb):
            self.Stop()

        def Start(self):
            """Start the shell."""
            if self._process is not None:
                raise RuntimeError('Persistent shell already running.')
            self._process = subprocess.Popen(self._cmd,
                                             stdin=subprocess.PIPE,
                                             stdout=subprocess.PIPE,
                                             shell=False)

        def WaitForReady(self):
            """Wait for the shell to be ready after starting.

      Sends an echo command, then waits until it gets a response.
      """
            self._process.stdin.write('echo\n')
            output_line = self._process.stdout.readline()
            while output_line.rstrip() != '':
                output_line = self._process.stdout.readline()

        def RunCommand(self, command, close=False):
            """Runs an ADB command and returns the output.

      Note that there can be approximately 40 ms of additional latency
      between sending the command and receiving the results if close=False
      due to the use of Nagle's algorithm in the TCP socket between the
      adb server and client. To avoid this extra latency, set close=True.

      Args:
        command: Command to send.
      Returns:
        The command output, given as a list of lines, and the exit code
      """

            if close:

                def run_cmd(cmd):
                    send_cmd = '( %s ); echo $?; exit;\n' % cmd.rstrip()
                    (output, _) = self._process.communicate(send_cmd)
                    self._process = None
                    for x in output.splitlines():
                        yield x

            else:

                def run_cmd(cmd):
                    send_cmd = '( %s ); echo DONE:$?;\n' % cmd.rstrip()
                    self._process.stdin.write(send_cmd)
                    while True:
                        output_line = self._process.stdout.readline().rstrip()
                        if output_line[:5] == 'DONE:':
                            yield output_line[5:]
                            break
                        yield output_line

            result = [
                line for line in run_cmd(command)
                if not _IsExtraneousLine(line, command)
            ]

            return (result[:-1], int(result[-1]))

        def Stop(self):
            """Stops the ADB process if it is still running."""
            if self._process is not None:
                self._process.stdin.write('exit\n')
                self._process = None

    @classmethod
    def GetAdbPath(cls):
        return cls._adb_path.read()

    @classmethod
    def Version(cls):
        return cls._adb_version.read()

    @classmethod
    def _BuildAdbCmd(cls, args, device_serial, cpu_affinity=None):
        if cpu_affinity is not None:
            cmd = ['taskset', '-c', str(cpu_affinity)]
        else:
            cmd = []
        cmd.append(cls.GetAdbPath())
        if device_serial is not None:
            cmd.extend(['-s', device_serial])
        cmd.extend(args)
        return cmd

    # pylint: disable=unused-argument
    @classmethod
    @decorators.WithTimeoutAndConditionalRetries(_ShouldRetryAdbCmd)
    def _RunAdbCmd(cls,
                   args,
                   timeout=None,
                   retries=None,
                   device_serial=None,
                   check_error=True,
                   cpu_affinity=None):
        # pylint: disable=no-member
        try:
            status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
                cls._BuildAdbCmd(args,
                                 device_serial,
                                 cpu_affinity=cpu_affinity),
                timeout_retry.CurrentTimeoutThreadGroup().GetRemainingTime())
        except OSError as e:
            if e.errno in (errno.ENOENT, errno.ENOEXEC):
                raise device_errors.NoAdbError(msg=str(e))
            else:
                raise

        if status != 0:
            raise device_errors.AdbCommandFailedError(args, output, status,
                                                      device_serial)
        # This catches some errors, including when the device drops offline;
        # unfortunately adb is very inconsistent with error reporting so many
        # command failures present differently.
        if check_error and output.startswith('error:'):
            raise device_errors.AdbCommandFailedError(args, output)
        return output

    # pylint: enable=unused-argument

    def _RunDeviceAdbCmd(self, args, timeout, retries, check_error=True):
        """Runs an adb command on the device associated with this object.

    Args:
      args: A list of arguments to adb.
      timeout: Timeout in seconds.
      retries: Number of retries.
      check_error: Check that the command doesn't return an error message. This
        does NOT check the exit status of shell commands.

    Returns:
      The output of the command.
    """
        return self._RunAdbCmd(args,
                               timeout=timeout,
                               retries=retries,
                               device_serial=self._device_serial,
                               check_error=check_error)

    def _IterRunDeviceAdbCmd(self, args, timeout):
        """Runs an adb command and returns an iterator over its output lines.

    Args:
      args: A list of arguments to adb.
      timeout: Timeout in seconds.

    Yields:
      The output of the command line by line.
    """
        return cmd_helper.IterCmdOutputLines(self._BuildAdbCmd(
            args, self._device_serial),
                                             timeout=timeout)

    def __eq__(self, other):
        """Consider instances equal if they refer to the same device.

    Args:
      other: The instance to compare equality with.

    Returns:
      True if the instances are considered equal, false otherwise.
    """
        return self._device_serial == str(other)

    def __str__(self):
        """The string representation of an instance.

    Returns:
      The device serial number as a string.
    """
        return self._device_serial

    def __repr__(self):
        return '%s(\'%s\')' % (self.__class__.__name__, self)

    # pylint: disable=unused-argument
    @classmethod
    def IsServerOnline(cls):
        status, output = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb'])
        output = [int(x) for x in output.split()]
        logging.info('PIDs for adb found: %r', output)
        return status == 0

    # pylint: enable=unused-argument

    @classmethod
    def KillServer(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        cls._RunAdbCmd(['kill-server'], timeout=timeout, retries=retries)

    @classmethod
    def StartServer(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        # CPU affinity is used to reduce adb instability http://crbug.com/268450
        cls._RunAdbCmd(['start-server'],
                       timeout=timeout,
                       retries=retries,
                       cpu_affinity=0)

    @classmethod
    def GetDevices(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """DEPRECATED. Refer to Devices(...) below."""
        # TODO(jbudorick): Remove this function once no more clients are using it.
        return cls.Devices(timeout=timeout, retries=retries)

    @classmethod
    def Devices(cls,
                desired_state=_READY_STATE,
                long_list=False,
                timeout=DEFAULT_TIMEOUT,
                retries=DEFAULT_RETRIES):
        """Get the list of active attached devices.

    Args:
      desired_state: If not None, limit the devices returned to only those
        in the given state.
      long_list: Whether to use the long listing format.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.

    Yields:
      AdbWrapper instances.
    """
        lines = cls._RawDevices(long_list=long_list,
                                timeout=timeout,
                                retries=retries)
        if long_list:
            return [[AdbWrapper(line[0])] + line[1:] for line in lines
                    if (len(line) >= 2 and (
                        not desired_state or line[1] == desired_state))]
        else:
            return [
                AdbWrapper(line[0]) for line in lines if (len(line) == 2 and (
                    not desired_state or line[1] == desired_state))
            ]

    @classmethod
    def _RawDevices(cls,
                    long_list=False,
                    timeout=DEFAULT_TIMEOUT,
                    retries=DEFAULT_RETRIES):
        cmd = ['devices']
        if long_list:
            cmd.append('-l')
        output = cls._RunAdbCmd(cmd, timeout=timeout, retries=retries)
        return [line.split() for line in output.splitlines()[1:]]

    def GetDeviceSerial(self):
        """Gets the device serial number associated with this object.

    Returns:
      Device serial number as a string.
    """
        return self._device_serial

    def Push(self, local, remote, timeout=60 * 5, retries=DEFAULT_RETRIES):
        """Pushes a file from the host to the device.

    Args:
      local: Path on the host filesystem.
      remote: Path on the device filesystem.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        VerifyLocalFileExists(local)

        if (distutils.version.LooseVersion(self.Version()) <
                distutils.version.LooseVersion('1.0.36')):

            # Different versions of adb handle pushing a directory to an existing
            # directory differently.

            # In the version packaged with the M SDK, 1.0.32, the following push:
            #   foo/bar -> /sdcard/foo/bar
            # where bar is an existing directory both on the host and the device
            # results in the contents of bar/ on the host being pushed to bar/ on
            # the device, i.e.
            #   foo/bar/A -> /sdcard/foo/bar/A
            #   foo/bar/B -> /sdcard/foo/bar/B
            #   ... etc.

            # In the version packaged with the N SDK, 1.0.36, the same push under
            # the same conditions results in a second bar/ directory being created
            # underneath the first bar/ directory on the device, i.e.
            #   foo/bar/A -> /sdcard/foo/bar/bar/A
            #   foo/bar/B -> /sdcard/foo/bar/bar/B
            #   ... etc.

            # In order to provide a consistent interface to clients, we check whether
            # the target is an existing directory on the device and, if so, modifies
            # the target passed to adb to emulate the behavior on 1.0.36 and above.

            # Note that this behavior may have started before 1.0.36; that's simply
            # the earliest version we've confirmed thus far.

            try:
                self.Shell('test -d %s' % remote,
                           timeout=timeout,
                           retries=retries)
                remote = posixpath.join(remote, posixpath.basename(local))
            except device_errors.AdbShellCommandFailedError:
                # The target directory doesn't exist on the device, so we can use it
                # without modification.
                pass

        self._RunDeviceAdbCmd(['push', local, remote], timeout, retries)

    def Pull(self, remote, local, timeout=60 * 5, retries=DEFAULT_RETRIES):
        """Pulls a file from the device to the host.

    Args:
      remote: Path on the device filesystem.
      local: Path on the host filesystem.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        cmd = ['pull', remote, local]
        self._RunDeviceAdbCmd(cmd, timeout, retries)
        try:
            VerifyLocalFileExists(local)
        except IOError:
            raise device_errors.AdbCommandFailedError(
                cmd,
                'File not found on host: %s' % local,
                device_serial=str(self))

    def Shell(self,
              command,
              expect_status=0,
              timeout=DEFAULT_TIMEOUT,
              retries=DEFAULT_RETRIES):
        """Runs a shell command on the device.

    Args:
      command: A string with the shell command to run.
      expect_status: (optional) Check that the command's exit status matches
        this value. Default is 0. If set to None the test is skipped.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.

    Returns:
      The output of the shell command as a string.

    Raises:
      device_errors.AdbCommandFailedError: If the exit status doesn't match
        |expect_status|.
    """
        if expect_status is None:
            args = ['shell', command]
        else:
            args = ['shell', '( %s );echo %%$?' % command.rstrip()]
        output = self._RunDeviceAdbCmd(args,
                                       timeout,
                                       retries,
                                       check_error=False)
        if expect_status is not None:
            output_end = output.rfind('%')
            if output_end < 0:
                # causes the status string to become empty and raise a ValueError
                output_end = len(output)

            try:
                status = int(output[output_end + 1:])
            except ValueError:
                logging.warning('exit status of shell command %r missing.',
                                command)
                raise device_errors.AdbShellCommandFailedError(
                    command,
                    output,
                    status=None,
                    device_serial=self._device_serial)
            output = output[:output_end]
            if status != expect_status:
                raise device_errors.AdbShellCommandFailedError(
                    command,
                    output,
                    status=status,
                    device_serial=self._device_serial)
        return output

    def IterShell(self, command, timeout):
        """Runs a shell command and returns an iterator over its output lines.

    Args:
      command: A string with the shell command to run.
      timeout: Timeout in seconds.

    Yields:
      The output of the command line by line.
    """
        args = ['shell', command]
        return cmd_helper.IterCmdOutputLines(self._BuildAdbCmd(
            args, self._device_serial),
                                             timeout=timeout)

    def Ls(self, path, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """List the contents of a directory on the device.

    Args:
      path: Path on the device filesystem.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.

    Returns:
      A list of pairs (filename, stat) for each file found in the directory,
      where the stat object has the properties: st_mode, st_size, and st_time.

    Raises:
      AdbCommandFailedError if |path| does not specify a valid and accessible
          directory in the device, or the output of "adb ls" command is less
          than four columns
    """
        def ParseLine(line, cmd):
            cols = line.split(None, 3)
            if len(cols) < 4:
                raise device_errors.AdbCommandFailedError(
                    cmd,
                    line,
                    "the output should be 4 columns, but is only %d columns" %
                    len(cols),
                    device_serial=self._device_serial)
            filename = cols.pop()
            stat = DeviceStat(*[int(num, base=16) for num in cols])
            return (filename, stat)

        cmd = ['ls', path]
        lines = self._RunDeviceAdbCmd(cmd, timeout=timeout,
                                      retries=retries).splitlines()
        if lines:
            return [ParseLine(line, cmd) for line in lines]
        else:
            raise device_errors.AdbCommandFailedError(
                cmd,
                'path does not specify an accessible directory in the device',
                device_serial=self._device_serial)

    def Logcat(self,
               clear=False,
               dump=False,
               filter_specs=None,
               logcat_format=None,
               ring_buffer=None,
               timeout=None,
               retries=DEFAULT_RETRIES):
        """Get an iterable over the logcat output.

    Args:
      clear: If true, clear the logcat.
      dump: If true, dump the current logcat contents.
      filter_specs: If set, a list of specs to filter the logcat.
      logcat_format: If set, the format in which the logcat should be output.
        Options include "brief", "process", "tag", "thread", "raw", "time",
        "threadtime", and "long"
      ring_buffer: If set, a list of alternate ring buffers to request.
        Options include "main", "system", "radio", "events", "crash" or "all".
        The default is equivalent to ["main", "system", "crash"].
      timeout: (optional) If set, timeout per try in seconds. If clear or dump
        is set, defaults to DEFAULT_TIMEOUT.
      retries: (optional) If clear or dump is set, the number of retries to
        attempt. Otherwise, does nothing.

    Yields:
      logcat output line by line.
    """
        cmd = ['logcat']
        use_iter = True
        if clear:
            cmd.append('-c')
            use_iter = False
        if dump:
            cmd.append('-d')
            use_iter = False
        if logcat_format:
            cmd.extend(['-v', logcat_format])
        if ring_buffer:
            for buffer_name in ring_buffer:
                cmd.extend(['-b', buffer_name])
        if filter_specs:
            cmd.extend(filter_specs)

        if use_iter:
            return self._IterRunDeviceAdbCmd(cmd, timeout)
        else:
            timeout = timeout if timeout is not None else DEFAULT_TIMEOUT
            return self._RunDeviceAdbCmd(cmd, timeout, retries).splitlines()

    def Forward(self,
                local,
                remote,
                allow_rebind=False,
                timeout=DEFAULT_TIMEOUT,
                retries=DEFAULT_RETRIES):
        """Forward socket connections from the local socket to the remote socket.

    Sockets are specified by one of:
      tcp:<port>
      localabstract:<unix domain socket name>
      localreserved:<unix domain socket name>
      localfilesystem:<unix domain socket name>
      dev:<character device name>
      jdwp:<process pid> (remote only)

    Args:
      local: The host socket.
      remote: The device socket.
      allow_rebind: A boolean indicating whether adb may rebind a local socket;
        otherwise, the default, an exception is raised if the local socket is
        already being forwarded.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        cmd = ['forward']
        if not allow_rebind:
            cmd.append('--no-rebind')
        cmd.extend([str(local), str(remote)])
        self._RunDeviceAdbCmd(cmd, timeout, retries)

    def ForwardRemove(self,
                      local,
                      timeout=DEFAULT_TIMEOUT,
                      retries=DEFAULT_RETRIES):
        """Remove a forward socket connection.

    Args:
      local: The host socket.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        self._RunDeviceAdbCmd(
            ['forward', '--remove', str(local)], timeout, retries)

    def ForwardList(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """List all currently forwarded socket connections.

    Args:
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        return self._RunDeviceAdbCmd(['forward', '--list'], timeout, retries)

    def JDWP(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """List of PIDs of processes hosting a JDWP transport.

    Args:
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.

    Returns:
      A list of PIDs as strings.
    """
        return [
            a.strip() for a in self._RunDeviceAdbCmd(['jdwp'], timeout,
                                                     retries).split('\n')
        ]

    def Install(self,
                apk_path,
                forward_lock=False,
                allow_downgrade=False,
                reinstall=False,
                sd_card=False,
                timeout=60 * 2,
                retries=DEFAULT_RETRIES):
        """Install an apk on the device.

    Args:
      apk_path: Host path to the APK file.
      forward_lock: (optional) If set forward-locks the app.
      allow_downgrade: (optional) If set, allows for downgrades.
      reinstall: (optional) If set reinstalls the app, keeping its data.
      sd_card: (optional) If set installs on the SD card.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        VerifyLocalFileExists(apk_path)
        cmd = ['install']
        if forward_lock:
            cmd.append('-l')
        if reinstall:
            cmd.append('-r')
        if sd_card:
            cmd.append('-s')
        if allow_downgrade:
            cmd.append('-d')
        cmd.append(apk_path)
        output = self._RunDeviceAdbCmd(cmd, timeout, retries)
        if 'Success' not in output:
            raise device_errors.AdbCommandFailedError(
                cmd, output, device_serial=self._device_serial)

    def InstallMultiple(self,
                        apk_paths,
                        forward_lock=False,
                        reinstall=False,
                        sd_card=False,
                        allow_downgrade=False,
                        partial=False,
                        timeout=60 * 2,
                        retries=DEFAULT_RETRIES):
        """Install an apk with splits on the device.

    Args:
      apk_paths: Host path to the APK file.
      forward_lock: (optional) If set forward-locks the app.
      reinstall: (optional) If set reinstalls the app, keeping its data.
      sd_card: (optional) If set installs on the SD card.
      allow_downgrade: (optional) Allow versionCode downgrade.
      partial: (optional) Package ID if apk_paths doesn't include all .apks.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        for path in apk_paths:
            VerifyLocalFileExists(path)
        cmd = ['install-multiple']
        if forward_lock:
            cmd.append('-l')
        if reinstall:
            cmd.append('-r')
        if sd_card:
            cmd.append('-s')
        if allow_downgrade:
            cmd.append('-d')
        if partial:
            cmd.extend(('-p', partial))
        cmd.extend(apk_paths)
        output = self._RunDeviceAdbCmd(cmd, timeout, retries)
        if 'Success' not in output:
            raise device_errors.AdbCommandFailedError(
                cmd, output, device_serial=self._device_serial)

    def Uninstall(self,
                  package,
                  keep_data=False,
                  timeout=DEFAULT_TIMEOUT,
                  retries=DEFAULT_RETRIES):
        """Remove the app |package| from the device.

    Args:
      package: The package to uninstall.
      keep_data: (optional) If set keep the data and cache directories.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        cmd = ['uninstall']
        if keep_data:
            cmd.append('-k')
        cmd.append(package)
        output = self._RunDeviceAdbCmd(cmd, timeout, retries)
        if 'Failure' in output:
            raise device_errors.AdbCommandFailedError(
                cmd, output, device_serial=self._device_serial)

    def Backup(self,
               path,
               packages=None,
               apk=False,
               shared=False,
               nosystem=True,
               include_all=False,
               timeout=DEFAULT_TIMEOUT,
               retries=DEFAULT_RETRIES):
        """Write an archive of the device's data to |path|.

    Args:
      path: Local path to store the backup file.
      packages: List of to packages to be backed up.
      apk: (optional) If set include the .apk files in the archive.
      shared: (optional) If set buckup the device's SD card.
      nosystem: (optional) If set exclude system applications.
      include_all: (optional) If set back up all installed applications and
        |packages| is optional.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        cmd = ['backup', '-f', path]
        if apk:
            cmd.append('-apk')
        if shared:
            cmd.append('-shared')
        if nosystem:
            cmd.append('-nosystem')
        if include_all:
            cmd.append('-all')
        if packages:
            cmd.extend(packages)
        assert bool(packages) ^ bool(include_all), (
            'Provide \'packages\' or set \'include_all\' but not both.')
        ret = self._RunDeviceAdbCmd(cmd, timeout, retries)
        VerifyLocalFileExists(path)
        return ret

    def Restore(self, path, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """Restore device contents from the backup archive.

    Args:
      path: Host path to the backup archive.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        VerifyLocalFileExists(path)
        self._RunDeviceAdbCmd(['restore'] + [path], timeout, retries)

    def WaitForDevice(self, timeout=60 * 5, retries=DEFAULT_RETRIES):
        """Block until the device is online.

    Args:
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        self._RunDeviceAdbCmd(['wait-for-device'], timeout, retries)

    def GetState(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """Get device state.

    Args:
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.

    Returns:
      One of 'offline', 'bootloader', or 'device'.
    """
        # TODO(jbudorick): Revert to using get-state once it doesn't cause a
        # a protocol fault.
        # return self._RunDeviceAdbCmd(['get-state'], timeout, retries).strip()

        lines = self._RawDevices(timeout=timeout, retries=retries)
        for line in lines:
            if len(line) >= 2 and line[0] == self._device_serial:
                return line[1]
        return 'offline'

    def GetDevPath(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """Gets the device path.

    Args:
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.

    Returns:
      The device path (e.g. usb:3-4)
    """
        return self._RunDeviceAdbCmd(['get-devpath'], timeout, retries)

    def Remount(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """Remounts the /system partition on the device read-write."""
        self._RunDeviceAdbCmd(['remount'], timeout, retries)

    def Reboot(self,
               to_bootloader=False,
               timeout=60 * 5,
               retries=DEFAULT_RETRIES):
        """Reboots the device.

    Args:
      to_bootloader: (optional) If set reboots to the bootloader.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        if to_bootloader:
            cmd = ['reboot-bootloader']
        else:
            cmd = ['reboot']
        self._RunDeviceAdbCmd(cmd, timeout, retries)

    def Root(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """Restarts the adbd daemon with root permissions, if possible.

    Args:
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.
    """
        output = self._RunDeviceAdbCmd(['root'], timeout, retries)
        if 'cannot' in output:
            raise device_errors.AdbCommandFailedError(
                ['root'], output, device_serial=self._device_serial)

    def Emu(self, cmd, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """Runs an emulator console command.

    See http://developer.android.com/tools/devices/emulator.html#console

    Args:
      cmd: The command to run on the emulator console.
      timeout: (optional) Timeout per try in seconds.
      retries: (optional) Number of retries to attempt.

    Returns:
      The output of the emulator console command.
    """
        if isinstance(cmd, basestring):
            cmd = [cmd]
        return self._RunDeviceAdbCmd(['emu'] + cmd, timeout, retries)

    def DisableVerity(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """Disable Marshmallow's Verity security feature"""
        output = self._RunDeviceAdbCmd(['disable-verity'], timeout, retries)
        if output and _VERITY_DISABLE_RE.search(output):
            raise device_errors.AdbCommandFailedError(
                ['disable-verity'], output, device_serial=self._device_serial)

    def EnableVerity(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
        """Enable Marshmallow's Verity security feature"""
        output = self._RunDeviceAdbCmd(['enable-verity'], timeout, retries)
        if output and _VERITY_ENABLE_RE.search(output):
            raise device_errors.AdbCommandFailedError(
                ['enable-verity'], output, device_serial=self._device_serial)

    @property
    def is_emulator(self):
        return _EMULATOR_RE.match(self._device_serial)

    @property
    def is_ready(self):
        try:
            return self.GetState() == _READY_STATE
        except device_errors.CommandFailedError:
            return False
Beispiel #9
0
  if not build_tools_path:
    raise dependency_manager.NoPathFoundError(build_tool,
                                              devil_env.GetPlatform())

  candidate_path = os.path.join(build_tools_path, build_tool)
  if not os.path.exists(candidate_path):
    raise dependency_manager.NoPathFoundError(build_tool,
                                              devil_env.GetPlatform())

  return candidate_path


def _FindBuildTools():
  android_sdk_path = devil_env.config.LocalPath('android_sdk')
  if not android_sdk_path:
    return None

  build_tools_contents = os.listdir(
      os.path.join(android_sdk_path, 'build-tools'))

  if not build_tools_contents:
    return None
  else:
    if len(build_tools_contents) > 1:
      build_tools_contents.sort()
    return os.path.join(android_sdk_path, 'build-tools',
                        build_tools_contents[-1])


_build_tools_path = lazy.WeakConstant(_FindBuildTools)
Beispiel #10
0
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This module wraps the Android Asset Packaging Tool."""

from devil.android.sdk import build_tools
from devil.utils import cmd_helper
from devil.utils import lazy

_aapt_path = lazy.WeakConstant(lambda: build_tools.GetPath('aapt'))


def _RunAaptCmd(args):
    """Runs an aapt command.

  Args:
    args: A list of arguments for aapt.

  Returns:
    The output of the command.
  """
    cmd = [_aapt_path.read()] + args
    status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
    if status != 0:
        raise Exception('Failed running aapt command: "%s" with output "%s".' %
                        (' '.join(cmd), output))
    return output


def Dump(what, apk, assets=None):
    """Returns the output of the aapt dump command.
Beispiel #11
0
class Fastboot(object):

    _fastboot_path = lazy.WeakConstant(
        lambda: devil_env.config.FetchPath('fastboot'))

    def __init__(self,
                 device_serial,
                 default_timeout=_DEFAULT_TIMEOUT,
                 default_retries=_DEFAULT_RETRIES):
        """Initializes the FastbootWrapper.

    Args:
      device_serial: The device serial number as a string.
    """
        if not device_serial:
            raise ValueError('A device serial must be specified')
        self._device_serial = str(device_serial)
        self._default_timeout = default_timeout
        self._default_retries = default_retries

    def _RunFastbootCommand(self, cmd):
        """Run a command line command using the fastboot android tool.

    Args:
      cmd: Command to run. Must be list of args, the first one being the command

    Returns:
      output of command.

    Raises:
      TypeError: If cmd is not of type list.
    """
        if type(cmd) == list:
            cmd = [self._fastboot_path.read(), '-s', self._device_serial] + cmd
        else:
            raise TypeError('Command for _RunFastbootCommand must be a list.')
        status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
        if int(status) != 0:
            raise device_errors.FastbootCommandFailedError(
                cmd, output, status, self._device_serial)
        return output

    @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0)
    def Flash(self, partition, image, timeout=None, retries=None):
        """Flash partition with img.

    Args:
      partition: Partition to be flashed.
      image: location of image to flash with.
    """
        self._RunFastbootCommand(['flash', partition, image])

    @decorators.WithTimeoutAndRetriesFromInstance()
    def Devices(self, timeout=None, retries=None):
        """Outputs list of devices in fastboot mode."""
        output = self._RunFastbootCommand(['devices'])
        return [line.split()[0] for line in output.splitlines()]

    @decorators.WithTimeoutAndRetriesFromInstance()
    def RebootBootloader(self, timeout=None, retries=None):
        """Reboot from fastboot, into fastboot."""
        self._RunFastbootCommand(['reboot-bootloader'])

    @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0)
    def Reboot(self, timeout=None, retries=None):
        """Reboot from fastboot to normal usage"""
        self._RunFastbootCommand(['reboot'])

    @decorators.WithTimeoutAndRetriesFromInstance()
    def SetOemOffModeCharge(self, value, timeout=None, retries=None):
        """Sets off mode charging

    Args:
      value: boolean value to set off-mode-charging on or off.
    """
        self._RunFastbootCommand(['oem', 'off-mode-charge', str(int(value))])
Beispiel #12
0
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import six

from devil.android.sdk import build_tools
from devil.utils import cmd_helper
from devil.utils import lazy

_dexdump_path = lazy.WeakConstant(lambda: build_tools.GetPath('dexdump'))


def DexDump(dexfiles, file_summary=False):
    """A wrapper around the Android SDK's dexdump tool.

  Args:
    dexfiles: The dexfile or list of dex files to dump.
    file_summary: Display summary information from the file header. (-f)

  Returns:
    An iterable over the output lines.
  """
    # TODO(jbudorick): Add support for more options as necessary.
    if isinstance(dexfiles, six.string_types):
        dexfiles = [dexfiles]
    args = [_dexdump_path.read()] + dexfiles
    if file_summary:
        args.append('-f')

    return cmd_helper.IterCmdOutputLines(args)