Ejemplo n.º 1
0
 def testPullDumps(self):
     """Test that minidumps can be pulled off the device and their mtimes set."""
     tempdir = tempfile.mkdtemp()
     try:
         with self._GetCRI() as cri:
             time_offset = cri.GetDeviceHostClockOffset()
             # Make sure we don't end up getting a negative timestamp when we pull
             # the dump.
             ts = abs(time_offset) + 1
             # Space to ensure that spaces are handled correctly.
             remote_path = '/tmp/dump dir/'
             quoted_remote_path = cmd_helper.SingleQuote(remote_path)
             cri.CROS_MINIDUMP_DIR = remote_path
             cri.RunCmdOnDevice(['mkdir', '-p', quoted_remote_path])
             # Set the mtime to one second after the epoch
             cri.RunCmdOnDevice([
                 'touch', '-d',
                 '@%d' % ts,
                 cmd_helper.SingleQuote(remote_path + 'test_dump')
             ])
             try:
                 cri.PullDumps(tempdir)
             finally:
                 cri.RmRF(remote_path)
             local_path = os.path.join(tempdir, 'test_dump')
             self.assertTrue(os.path.exists(local_path))
             self.assertEqual(os.path.getmtime(local_path),
                              ts - time_offset)
     finally:
         shutil.rmtree(tempdir)
Ejemplo n.º 2
0
    def PullDumps(self, host_dir):
        """Pulls any minidumps from the device/emulator to the host.

    Skips pulling any dumps that have already been pulled. The modification time
    of any pulled dumps will be set to the modification time of the dump on the
    device/emulator, offset by any difference in clocks between the device and
    host.

    Args:
      host_dir: The directory on the host where the dumps will be copied to.
    """
        # The device/emulator's clock might be off from the host, so calculate an
        # offset that can be added to the host time to get the corresponding device
        # time.
        time_offset = self.GetDeviceHostClockOffset()

        stdout, _ = self.RunCmdOnDevice(
            ['ls', '-1',
             cmd_helper.SingleQuote(self.CROS_MINIDUMP_DIR)])
        device_dumps = stdout.splitlines()
        for dump_filename in device_dumps:
            host_path = os.path.join(host_dir, dump_filename)
            if not os.path.exists(host_path):
                device_path = cmd_helper.SingleQuote(
                    posixpath.join(self.CROS_MINIDUMP_DIR, dump_filename))
                self.GetFile(device_path, host_path)
                # Set the local version's modification time to the device's.
                stdout, _ = self.RunCmdOnDevice(
                    ['ls', '--time-style', '+%s', '-l', device_path])
                stdout = stdout.strip()
                # We expect whitespace-separated fields in this order:
                # mode, links, owner, group, size, mtime, filename.
                # Offset by the difference of the device and host clocks.
                mtime = int(stdout.split()[5]) + time_offset
                os.utime(host_path, (mtime, mtime))
Ejemplo n.º 3
0
    def Push(self, local, remote, **kwargs):
        """Pushes an object from the host to the gce instance.

    Args:
      local: Path on the host filesystem.
      remote: Path on the instance filesystem.
    """
        adb_wrapper.VerifyLocalFileExists(_SSH_KEY_FILE)
        adb_wrapper.VerifyLocalFileExists(local)
        if os.path.isdir(local):
            self.Shell('mkdir -p %s' % cmd_helper.SingleQuote(remote))

            # When the object to be pushed is a directory, adb merges the source dir
            # with the destination dir. So if local is a dir, just scp its contents.
            for f in os.listdir(local):
                self._PushObject(os.path.join(local, f),
                                 os.path.join(remote, f))
                self.Shell('chmod 777 %s' %
                           cmd_helper.SingleQuote(os.path.join(remote, f)))
        else:
            parent_dir = remote[0:remote.rfind('/')]
            if parent_dir:
                self.Shell('mkdir -p %s' % cmd_helper.SingleQuote(parent_dir))
            self._PushObject(local, remote)
            self.Shell('chmod 777 %s' % cmd_helper.SingleQuote(remote))
Ejemplo n.º 4
0
 def testGetFileQuotes(self):  # pylint: disable=no-self-use
   with self._GetCRI() as cri:
     f = tempfile.NamedTemporaryFile()
     cri.GetFile(cmd_helper.SingleQuote('/etc/lsb-release'), f.name)
     with open(f.name, 'r') as f2:
       res = f2.read()
       self.assertTrue('CHROMEOS' in res)
Ejemplo n.º 5
0
 def victim():
     trigger_cmd = 'echo -n %s > %s; sleep 20' % (
         cmd_helper.SingleQuote(trigger_text),
         cmd_helper.SingleQuote(trigger_file.name))
     crash_handler.RetryOnSystemCrash(
         lambda d: d.RunShellCommand(trigger_cmd,
                                     shell=True,
                                     check_return=True,
                                     retries=1,
                                     as_root=True,
                                     timeout=180),
         device=self.device)
     self.assertEquals(
         trigger_text,
         self.device.ReadFile(trigger_file.name, retries=0).strip())
     return True
Ejemplo n.º 6
0
    def __init__(self,
                 adb,
                 suffix='',
                 prefix='temp_file',
                 dir='/data/local/tmp'):
        """Find an unused temporary file path on the presentation.device.

    When this object is closed, the file will be deleted on the presentation.device.

    Args:
      adb: An instance of AdbWrapper
      suffix: The suffix of the name of the temp file.
      prefix: The prefix of the name of the temp file.
      dir: The directory on the presentation.device where to place the temp file.
    Raises:
      ValueError if any of suffix, prefix, or dir are None.
    """
        if None in (dir, prefix, suffix):
            m = 'Provided None path component. (dir: %s, prefix: %s, suffix: %s)' % (
                dir, prefix, suffix)
            raise ValueError(m)

        self._adb = adb
        # Python's random module use 52-bit numbers according to its docs.
        random_hex = hex(random.randint(0, 2**52))[2:]
        self.name = posixpath.join(dir,
                                   '%s-%s%s' % (prefix, random_hex, suffix))
        self.name_quoted = cmd_helper.SingleQuote(self.name)
Ejemplo n.º 7
0
    def __init__(self,
                 adb,
                 suffix='',
                 prefix='temp_file',
                 dir='/data/local/tmp'):
        """Find an unused temporary file path on the device.

    When this object is closed, the file will be deleted on the device.

    Args:
      adb: An instance of AdbWrapper
      suffix: The suffix of the name of the temporary file.
      prefix: The prefix of the name of the temporary file.
      dir: The directory on the device in which the temporary file should be
        placed.
    Raises:
      ValueError if any of suffix, prefix, or dir are None.
    """
        if None in (dir, prefix, suffix):
            m = 'Provided None path component. (dir: %s, prefix: %s, suffix: %s)' % (
                dir, prefix, suffix)
            raise ValueError(m)

        self._adb = adb
        # Python's random module use 52-bit numbers according to its docs.
        self.name = _GenerateName(prefix, suffix, dir)
        self.name_quoted = cmd_helper.SingleQuote(self.name)
  def testMinidumpsFromTestRemoved(self):
    """Tests that any minidumps generated during a test are removed."""
    browser = self._CreateBrowser()
    cri = browser._platform_backend.cri
    # This is expected to fail if running locally and the root is not writable,
    # as we can't reboot in order to make it writable.
    if cri.local:
      return
    remote_path = cmd_helper.SingleQuote(
        posixpath.join(cri.CROS_MINIDUMP_DIR, 'test_dump'))
    if cri.FileExistsOnDevice(remote_path):
      cri.RmRF(remote_path)
    browser.SetUpEnvironment(options_for_unittests.GetCopy().browser_options)

    # SetUpEnvironment may finish too early, CROS_MINIDUMP_DIR might not exist
    # yet. First waits for its existence, and then create a test dump.
    def minidump_dir_exists():
      return cri.FileExistsOnDevice(
          cmd_helper.SingleQuote(cri.CROS_MINIDUMP_DIR))
    py_utils.WaitFor(minidump_dir_exists, timeout=10)

    cri.RunCmdOnDevice(['touch', remote_path])
    self.assertTrue(cri.FileExistsOnDevice(remote_path))
    browser._TearDownEnvironment()
    self.assertFalse(cri.FileExistsOnDevice(remote_path))
Ejemplo n.º 9
0
def main():
  parser = argparse.ArgumentParser(description=__doc__)
  parser.usage = '''%(prog)s --name FILENAME [--device SERIAL] [flags...]

No flags: Prints existing command-line file.
Empty string: Deletes command-line file.
Otherwise: Writes command-line file.

'''
  parser.add_argument('--name', required=True,
                      help='Name of file where to store flags on the device.')
  parser.add_argument('-e', '--executable', dest='executable', default='chrome',
                      help='(deprecated) No longer used.')
  script_common.AddEnvironmentArguments(parser)
  script_common.AddDeviceArguments(parser)
  logging_common.AddLoggingArguments(parser)

  args, remote_args = parser.parse_known_args()
  devil_chromium.Initialize(adb_path=args.adb_path)
  logging_common.InitializeLogging(args)

  devices = device_utils.DeviceUtils.HealthyDevices(device_arg=args.devices,
                                                    default_retries=0)
  all_devices = device_utils.DeviceUtils.parallel(devices)

  if not remote_args:
    # No args == do not update, just print flags.
    remote_args = None
    action = ''
  elif len(remote_args) == 1 and not remote_args[0]:
    # Single empty string arg == delete flags
    remote_args = []
    action = 'Deleted command line file. '
  else:
    action = 'Wrote command line file. '

  def update_flags(device):
    CheckBuildTypeSupportsFlags(device, args.name)
    changer = flag_changer.FlagChanger(device, args.name)
    if remote_args is not None:
      flags = changer.ReplaceFlags(remote_args)
    else:
      flags = changer.GetCurrentFlags()
    return (device, device.build_description, flags)

  updated_values = all_devices.pMap(update_flags).pGet(None)

  print('%sCurrent flags (in %s):' % (action, args.name))
  for d, desc, flags in updated_values:
    if flags:
      # Shell-quote flags for easy copy/paste as new args on the terminal.
      quoted_flags = ' '.join(cmd_helper.SingleQuote(f) for f in sorted(flags))
    else:
      quoted_flags = '( empty )'
    print('  %s (%s): %s' % (d, desc, quoted_flags))

  return 0
Ejemplo n.º 10
0
 def __init__(self, args, desc=None, actual_version=None, min_version=None):
   adb_cmd = ' '.join(cmd_helper.SingleQuote(arg) for arg in args)
   desc = desc or 'not supported'
   if min_version:
     desc += ' prior to %s' % min_version
   if actual_version:
     desc += ' (actual: %s)' % actual_version
   super(AdbVersionError,
         self).__init__(message='adb %s: %s' % (adb_cmd, desc))
Ejemplo n.º 11
0
 def _Record(self):
     cmd = ['screenrecord', '--verbose', '--bit-rate', str(self._bit_rate)]
     if self._rotate:
         cmd += ['--rotate']
     if self._size:
         cmd += ['--size', '%dx%d' % self._size]
     cmd += [self._device_file]
     for line in self._device.adb.IterShell(
             ' '.join(cmd_helper.SingleQuote(i) for i in cmd), None):
         if line.startswith('Content area is '):
             self._started.set()
Ejemplo n.º 12
0
    def __init__(self,
                 adb,
                 suffix='',
                 prefix='temp_file',
                 dir='/data/local/tmp'):
        """Find an unused temporary file path in the devices external directory.

    When this object is closed, the file will be deleted on the device.

    Args:
      adb: An instance of AdbWrapper
      suffix: The suffix of the name of the temp file.
      prefix: The prefix of the name of the temp file.
      dir: The directory on the device where to place the temp file.
    """
        self._adb = adb
        command = _COMMAND_TEMPLATE.format(
            dir=cmd_helper.SingleQuote(dir),
            suffix=cmd_helper.SingleQuote(suffix),
            prefix=cmd_helper.SingleQuote(prefix))
        self.name = self._adb.Shell(command)
        self.name_quoted = cmd_helper.SingleQuote(self.name)
Ejemplo n.º 13
0
 def testExistingMinidumpsMoved(self):
   """Tests that existing minidumps are moved while testing, but put back."""
   browser = self._CreateBrowser()
   cri = browser._platform_backend.cri
   # This is expected to fail if running locally and the root is not writable,
   # as we can't reboot in order to make it writable.
   if cri.local and not cri.root_is_writable:
     return
   remote_path = cmd_helper.SingleQuote(
       posixpath.join(cri.CROS_MINIDUMP_DIR, 'test_dump'))
   cri.RunCmdOnDevice(['touch', remote_path])
   self.assertTrue(cri.FileExistsOnDevice(remote_path))
   browser.SetUpEnvironment(options_for_unittests.GetCopy().browser_options)
   self.assertFalse(cri.FileExistsOnDevice(remote_path))
   browser._TearDownEnvironment()
   self.assertTrue(cri.FileExistsOnDevice(remote_path))
Ejemplo n.º 14
0
    def __init__(self, adb, suffix='', prefix='tmp', dir='/data/local/tmp'):
        """Find an unused temporary directory path on the device. The directory is
    not created until it is used with a 'with' statement.

    When this object is closed, the directory will be deleted on the device.

    Args:
      adb: An instance of AdbWrapper
      suffix: The suffix of the name of the temporary directory.
      prefix: The prefix of the name of the temporary directory.
      dir: The directory on the device where to place the temporary directory.
    Raises:
      ValueError if any of suffix, prefix, or dir are None.
    """
        self._adb = adb
        self.name = _GenerateName(prefix, suffix, dir)
        self.name_quoted = cmd_helper.SingleQuote(self.name)
Ejemplo n.º 15
0
 def __init__(self, args, output, status=None, device_serial=None,
              message=None):
   self.args = args
   self.output = output
   self.status = status
   if not message:
     adb_cmd = ' '.join(cmd_helper.SingleQuote(arg) for arg in self.args)
     segments = ['adb %s: failed ' % adb_cmd]
     if status:
       segments.append('with exit status %s ' % self.status)
     if output:
       segments.append('and output:\n')
       segments.extend('- %s\n' % line for line in output.splitlines())
     else:
       segments.append('and no output.')
     message = ''.join(segments)
   super(_BaseCommandFailedError, self).__init__(message, device_serial)
Ejemplo n.º 16
0
 def testMinidumpsFromTestRemoved(self):
     """Tests that any minidumps generated during a test are removed."""
     browser = self._CreateBrowser()
     cri = browser._platform_backend.cri
     # This is expected to fail if running locally and the root is not writable,
     # as we can't reboot in order to make it writable.
     if cri.local:
         return
     remote_path = cmd_helper.SingleQuote(
         posixpath.join(cri.CROS_MINIDUMP_DIR, 'test_dump'))
     if cri.FileExistsOnDevice(remote_path):
         cri.RmRF(remote_path)
     browser.SetUpEnvironment(
         options_for_unittests.GetCopy().browser_options)
     cri.RunCmdOnDevice(['touch', remote_path])
     self.assertTrue(cri.FileExistsOnDevice(remote_path))
     browser._TearDownEnvironment()
     self.assertFalse(cri.FileExistsOnDevice(remote_path))
Ejemplo n.º 17
0
def _Requote(s):
  """Replaces any existing quotes around a string with single quotes.

  No-ops if the given object is not a string or otherwise does not have a
  .strip() method.

  Examples: "foo" -> 'foo', '"foo"' -> 'foo'

  Args:
    s: The string to replace quotes on.

  Returns:
    |s| with trailing/leading quotes replaced with a single pair of single
    quotes.
  """
  if not hasattr(s, 'strip'):
    return s
  return cmd_helper.SingleQuote(_Unquote(s))
Ejemplo n.º 18
0
    def __init__(self,
                 adb,
                 suffix='',
                 prefix='temp_file',
                 dir='/data/local/tmp'):
        """Find an unused temporary file path on the device.

    When this object is closed, the file will be deleted on the device.

    Args:
      adb: An instance of AdbWrapper
      suffix: The suffix of the name of the temp file.
      prefix: The prefix of the name of the temp file.
      dir: The directory on the device where to place the temp file.
    """
        self._adb = adb
        # Python's random module use 52-bit numbers according to its docs.
        random_hex = hex(random.randint(0, 2**52))[2:]
        self.name = posixpath.join(dir,
                                   '%s-%s%s' % (prefix, random_hex, suffix))
        self.name_quoted = cmd_helper.SingleQuote(self.name)
Ejemplo n.º 19
0
def main():
  parser = argparse.ArgumentParser(description=__doc__)
  parser.usage = '''%(prog)s --device-path PATH [--device SERIAL] [flags...]

No flags: Prints existing command-line file.
Empty string: Deletes command-line file.
Otherwise: Writes command-line file.

'''
  parser.add_argument('-d', '--device', dest='device',
                      help='Target device for apk to install on.')
  parser.add_argument('--device-path', required=True,
                      help='Remote path to flags file.')
  parser.add_argument('-e', '--executable', dest='executable', default='chrome',
                      help='Name of the executable.')
  args, remote_args = parser.parse_known_args()

  devil_chromium.Initialize()

  as_root = not args.device_path.startswith('/data/local/tmp/')

  if args.device:
    devices = [device_utils.DeviceUtils(args.device, default_retries=0)]
  else:
    devices = device_utils.DeviceUtils.HealthyDevices(default_retries=0)
    if not devices:
      raise device_errors.NoDevicesError()

  all_devices = device_utils.DeviceUtils.parallel(devices)

  def print_args():
    def read_flags(device):
      try:
        return device.ReadFile(args.device_path, as_root=as_root).rstrip()
      except device_errors.AdbCommandFailedError:
        return ''  # File might not exist.

    descriptions = all_devices.pMap(lambda d: d.build_description).pGet(None)
    flags = all_devices.pMap(read_flags).pGet(None)
    for d, desc, flags in zip(devices, descriptions, flags):
      print '  %s (%s): %r' % (d, desc, flags)

  # No args == print flags.
  if not remote_args:
    print 'Existing flags (in %s):' % args.device_path
    print_args()
    return 0

  # Empty string arg == delete flags file.
  if len(remote_args) == 1 and not remote_args[0]:
    def delete_flags(device):
      device.RunShellCommand(['rm', '-f', args.device_path], as_root=as_root)
    all_devices.pMap(delete_flags).pGet(None)
    print 'Deleted %s' % args.device_path
    return 0

  # Set flags.
  quoted_args = ' '.join(cmd_helper.SingleQuote(x) for x in remote_args)
  flags_str = ' '.join([args.executable, quoted_args])

  def write_flags(device):
    device.WriteFile(args.device_path, flags_str, as_root=as_root)
    device.RunShellCommand(['chmod', '0664', args.device_path], as_root=as_root)

  all_devices.pMap(write_flags).pGet(None)
  print 'Wrote flags to %s' % args.device_path
  print_args()
  return 0
Ejemplo n.º 20
0
class PossibleCrOSBrowser(possible_browser.PossibleBrowser):
    """A launchable CrOS browser instance."""

    # The path contains spaces, so we need to quote it. We don't join it with
    # anything in this file, so we can quote it here instead of everywhere it's
    # used.
    _CROS_MINIDUMP_DIR = cmd_helper.SingleQuote(
        cros_interface.CrOSInterface.CROS_MINIDUMP_DIR)

    _DEFAULT_CHROME_ENV = [
        'CHROME_HEADLESS=1',
        'BREAKPAD_DUMP_LOCATION=%s' % _CROS_MINIDUMP_DIR,
    ]

    def __init__(self, browser_type, finder_options, cros_platform, is_guest):
        super(PossibleCrOSBrowser, self).__init__(
            browser_type,
            'lacros' if browser_type == 'lacros-chrome' else 'cros', True)
        assert browser_type in FindAllBrowserTypes(), (
            'Please add %s to cros_browser_finder.FindAllBrowserTypes()' %
            browser_type)
        del finder_options
        self._platform = cros_platform
        self._platform_backend = (cros_platform._platform_backend)  # pylint: disable=protected-access
        self._is_guest = is_guest

        self._existing_minidump_dir = None
        # There's no way to automatically determine the build directory, as
        # unlike Android, we're not responsible for installing the browser. If
        # we're running on a bot, then the CrOS wrapper script will set this
        # accordingly, and normal users can pass --chromium-output-dir to have
        # this set in browser_options.
        self._build_dir = os.environ.get('CHROMIUM_OUTPUT_DIR')

    def __repr__(self):
        return 'PossibleCrOSBrowser(browser_type=%s)' % self.browser_type

    @property
    def browser_directory(self):
        result = self._platform_backend.cri.GetChromeProcess()
        if result and 'path' in result:
            return posixpath.dirname(result['path'])
        return None

    @property
    def profile_directory(self):
        return '/home/chronos/Default'

    def _InitPlatformIfNeeded(self):
        pass

    def _GetPathsForOsPageCacheFlushing(self):
        return [self.profile_directory, self.browser_directory]

    def SetUpEnvironment(self, browser_options):
        super(PossibleCrOSBrowser, self).SetUpEnvironment(browser_options)

        # Copy extensions to temp directories on the device.
        # Note that we also perform this copy locally to ensure that
        # the owner of the extensions is set to chronos.
        cri = self._platform_backend.cri
        for extension in self._browser_options.extensions_to_load:
            extension_dir = cri.RunCmdOnDevice(
                ['mktemp', '-d', '/tmp/extension_XXXXX'])[0].rstrip()
            # TODO(crbug.com/807645): We should avoid having mutable objects
            # stored within the browser options.
            extension.local_path = posixpath.join(
                extension_dir, os.path.basename(extension.path))
            cri.PushFile(extension.path, extension_dir)
            cri.Chown(extension_dir)

        # Move any existing crash dumps temporarily so that they don't get deleted.
        self._existing_minidump_dir = ('/tmp/existing_minidumps_%s' %
                                       _GetRandomHash())
        cri.RunCmdOnDevice(
            ['mv', self._CROS_MINIDUMP_DIR, self._existing_minidump_dir])

        def browser_ready():
            return cri.GetChromePid() is not None

        cri.RestartUI(self._browser_options.clear_enterprise_policy)
        py_utils.WaitFor(browser_ready, timeout=20)

        # Delete test user's cryptohome vault (user data directory).
        if not self._browser_options.dont_override_profile:
            cri.RunCmdOnDevice([
                'cryptohome', '--action=remove', '--force',
                '--user=%s' % self._browser_options.username
            ])

    def _TearDownEnvironment(self):
        cri = self._platform_backend.cri
        for extension in self._browser_options.extensions_to_load:
            cri.RmRF(posixpath.dirname(extension.local_path))

        # Move back any dumps that existed before we started the test.
        cri.RmRF(self._CROS_MINIDUMP_DIR)
        cri.RunCmdOnDevice(
            ['mv', self._existing_minidump_dir, self._CROS_MINIDUMP_DIR])

    def Create(self):
        # Init the LocalFirstBinaryManager if this is the first time we're creating
        # a browser.
        if local_first_binary_manager.LocalFirstBinaryManager.NeedsInit():
            local_first_binary_manager.LocalFirstBinaryManager.Init(
                self._build_dir,
                None,
                'linux',
                platform.machine(),
                # TODO(crbug.com/1084334): Remove crashpad_database_util once the
                # locally compiled version works.
                ignored_dependencies=['crashpad_database_util'])

        startup_args = self.GetBrowserStartupArgs(self._browser_options)

        os_browser_backend = cros_browser_backend.CrOSBrowserBackend(
            self._platform_backend,
            self._browser_options,
            self.browser_directory,
            self.profile_directory,
            self._is_guest,
            self._DEFAULT_CHROME_ENV,
            build_dir=self._build_dir)

        if self._browser_options.create_browser_with_oobe:
            return cros_browser_with_oobe.CrOSBrowserWithOOBE(
                os_browser_backend, self._platform_backend, startup_args)
        os_browser_backend.Start(startup_args)

        if self._app_type == 'lacros-chrome':
            lacros_chrome_browser_backend = lacros_browser_backend.LacrosBrowserBackend(
                self._platform_backend,
                self._browser_options,
                self.browser_directory,
                self.profile_directory,
                self._DEFAULT_CHROME_ENV,
                os_browser_backend,
                build_dir=self._build_dir)
            return browser.Browser(lacros_chrome_browser_backend,
                                   self._platform_backend, startup_args)
        else:
            return browser.Browser(os_browser_backend, self._platform_backend,
                                   startup_args)

    def GetBrowserStartupArgs(self, browser_options):
        startup_args = chrome_startup_args.GetFromBrowserOptions(
            browser_options)

        startup_args.extend(
            chrome_startup_args.GetReplayArgs(
                self._platform_backend.network_controller_backend))

        vmodule = ','.join('%s=2' % pattern for pattern in [
            '*/chromeos/net/*', '*/chromeos/login/*',
            'chrome_browser_main_posix'
        ])

        startup_args.extend([
            '--enable-smooth-scrolling',
            '--enable-threaded-compositing',
            # Allow devtools to connect to chrome.
            '--remote-debugging-port=0',
            # Open a maximized window.
            '--start-maximized',
            # Disable sounds.
            '--ash-disable-system-sounds',
            # Skip user image selection screen, and post login screens.
            '--oobe-skip-postlogin',
            # Debug logging.
            '--vmodule=%s' % vmodule,
            # Enable crash dumping.
            '--enable-crash-reporter-for-testing',
        ])

        if self._app_type == 'lacros-chrome':
            startup_args.extend(
                ['--lacros-mojo-socket-for-testing=/tmp/lacros.sock'])

        if browser_options.mute_audio:
            startup_args.append('--mute-audio')

        if not browser_options.expect_policy_fetch:
            startup_args.append('--allow-failed-policy-fetch-for-test')

        # If we're using GAIA, skip to login screen, enable GaiaActionButtons
        # feature, and do not disable GAIA services.
        if browser_options.gaia_login:
            startup_args.append('--oobe-skip-to-login')
            startup_args.append('--enable-features=GaiaActionButtons')
        elif browser_options.disable_gaia_services:
            startup_args.append('--disable-gaia-services')

        trace_config_file = (self._platform_backend.tracing_controller_backend.
                             GetChromeTraceConfigFile())
        if trace_config_file:
            startup_args.append('--trace-config-file=%s' % trace_config_file)

        return startup_args

    def SupportsOptions(self, browser_options):
        return (len(browser_options.extensions_to_load)
                == 0) or not self._is_guest

    def UpdateExecutableIfNeeded(self):
        pass
 def minidump_dir_exists():
   return cri.FileExistsOnDevice(
       cmd_helper.SingleQuote(cri.CROS_MINIDUMP_DIR))
Ejemplo n.º 22
0
class PossibleCrOSBrowser(possible_browser.PossibleBrowser):
    """A launchable CrOS browser instance."""

    _CHROME_ENV_FILEPATH = '/etc/chrome_dev.conf'
    # The path contains spaces, so we need to quote it. We don't join it with
    # anything in this file, so we can quote it here instead of everywhere it's
    # used.
    _CROS_MINIDUMP_DIR = cmd_helper.SingleQuote(
        cros_interface.CrOSInterface.CROS_MINIDUMP_DIR)
    _EXISTING_ENV_FILEPATH = '/tmp/existing_chrome_env.conf'
    _EXISTING_MINIDUMP_DIR = '/tmp/existing_minidumps/'

    _DEFAULT_CHROME_ENV = [
        'CHROME_HEADLESS=1',
    ]

    def __init__(self, browser_type, finder_options, cros_platform, is_guest):
        super(PossibleCrOSBrowser, self).__init__(browser_type, 'cros', True)
        assert browser_type in FindAllBrowserTypes(), (
            'Please add %s to cros_browser_finder.FindAllBrowserTypes()' %
            browser_type)
        del finder_options
        self._platform = cros_platform
        self._platform_backend = (cros_platform._platform_backend)  # pylint: disable=protected-access
        self._is_guest = is_guest

        # --chromium-output-dir also sets CHROMIUM_OUTPUT_DIR in browser_options.
        self._build_dir = os.environ.get('CHROMIUM_OUTPUT_DIR')

    def __repr__(self):
        return 'PossibleCrOSBrowser(browser_type=%s)' % self.browser_type

    @property
    def browser_directory(self):
        result = self._platform_backend.cri.GetChromeProcess()
        if result and 'path' in result:
            return posixpath.dirname(result['path'])
        return None

    @property
    def profile_directory(self):
        return '/home/chronos/Default'

    def _InitPlatformIfNeeded(self):
        pass

    def _GetPathsForOsPageCacheFlushing(self):
        return [self.profile_directory, self.browser_directory]

    def SetUpEnvironment(self, browser_options):
        super(PossibleCrOSBrowser, self).SetUpEnvironment(browser_options)

        # Copy extensions to temp directories on the device.
        # Note that we also perform this copy locally to ensure that
        # the owner of the extensions is set to chronos.
        cri = self._platform_backend.cri
        for extension in self._browser_options.extensions_to_load:
            extension_dir = cri.RunCmdOnDevice(
                ['mktemp', '-d', '/tmp/extension_XXXXX'])[0].rstrip()
            # TODO(crbug.com/807645): We should avoid having mutable objects
            # stored within the browser options.
            extension.local_path = posixpath.join(
                extension_dir, os.path.basename(extension.path))
            cri.PushFile(extension.path, extension_dir)
            cri.Chown(extension_dir)

        # Move any existing crash dumps temporarily so that they don't get deleted.
        if cri.FileExistsOnDevice(self._EXISTING_MINIDUMP_DIR):
            cri.RmRF(self._EXISTING_MINIDUMP_DIR)
        cri.RunCmdOnDevice(
            ['mv', self._CROS_MINIDUMP_DIR, self._EXISTING_MINIDUMP_DIR])

        self._SetChromeEnvironment()

        def browser_ready():
            return cri.GetChromePid() is not None

        cri.RestartUI(self._browser_options.clear_enterprise_policy)
        py_utils.WaitFor(browser_ready, timeout=20)

        # Delete test user's cryptohome vault (user data directory).
        if not self._browser_options.dont_override_profile:
            cri.RunCmdOnDevice([
                'cryptohome', '--action=remove', '--force',
                '--user=%s' % self._browser_options.username
            ])

    def _TearDownEnvironment(self):
        cri = self._platform_backend.cri
        for extension in self._browser_options.extensions_to_load:
            cri.RmRF(posixpath.dirname(extension.local_path))

        # Move back any dumps that existed before we started the test.
        cri.RmRF(self._CROS_MINIDUMP_DIR)
        cri.RunCmdOnDevice(
            ['mv', self._EXISTING_MINIDUMP_DIR, self._CROS_MINIDUMP_DIR])

        self._RestoreChromeEnvironment()

    def Create(self):
        startup_args = self.GetBrowserStartupArgs(self._browser_options)

        browser_backend = cros_browser_backend.CrOSBrowserBackend(
            self._platform_backend, self._browser_options,
            self.browser_directory, self.profile_directory, self._is_guest,
            self._build_dir)

        if self._browser_options.create_browser_with_oobe:
            return cros_browser_with_oobe.CrOSBrowserWithOOBE(
                browser_backend, self._platform_backend, startup_args)
        return browser.Browser(browser_backend, self._platform_backend,
                               startup_args)

    def GetBrowserStartupArgs(self, browser_options):
        startup_args = chrome_startup_args.GetFromBrowserOptions(
            browser_options)

        startup_args.extend(
            chrome_startup_args.GetReplayArgs(
                self._platform_backend.network_controller_backend))

        vmodule = ','.join('%s=2' % pattern for pattern in [
            '*/chromeos/net/*', '*/chromeos/login/*',
            'chrome_browser_main_posix'
        ])

        startup_args.extend([
            '--enable-smooth-scrolling',
            '--enable-threaded-compositing',
            # Allow devtools to connect to chrome.
            '--remote-debugging-port=0',
            # Open a maximized window.
            '--start-maximized',
            # Disable sounds.
            '--ash-disable-system-sounds',
            # Skip user image selection screen, and post login screens.
            '--oobe-skip-postlogin',
            # Debug logging.
            '--vmodule=%s' % vmodule,
            # Enable crash dumping.
            '--enable-crash-reporter-for-testing',
        ])

        if browser_options.mute_audio:
            startup_args.append('--mute-audio')

        if not browser_options.expect_policy_fetch:
            startup_args.append('--allow-failed-policy-fetch-for-test')

        # If we're using GAIA, skip to login screen, and do not disable GAIA
        # services.
        if browser_options.gaia_login:
            startup_args.append('--oobe-skip-to-login')
        elif browser_options.disable_gaia_services:
            startup_args.append('--disable-gaia-services')

        trace_config_file = (self._platform_backend.tracing_controller_backend.
                             GetChromeTraceConfigFile())
        if trace_config_file:
            startup_args.append('--trace-config-file=%s' % trace_config_file)

        return startup_args

    def SupportsOptions(self, browser_options):
        return (len(browser_options.extensions_to_load)
                == 0) or not self._is_guest

    def UpdateExecutableIfNeeded(self):
        pass

    def _SetChromeEnvironment(self, env=None):
        """Sets environment variables, command line flags, etc. for Chrome.

    RestartUI() must be called sometime afterwards for the changes to actually
    take effect.
    """
        if env is None:
            env = self._DEFAULT_CHROME_ENV
        assert isinstance(env, list)

        cri = self._platform_backend.cri
        cri.MakeRootReadWriteIfNecessary()
        if not cri.root_is_writable:
            logging.error(
                'Failed to set root to read-write. Functionality such as '
                'stack symbolization will be broken.')
            return
        cri.RunCmdOnDevice(
            ['mv', self._CHROME_ENV_FILEPATH, self._EXISTING_ENV_FILEPATH])

        env_string = '\n'.join(env)
        cri.PushContents(env_string, self._CHROME_ENV_FILEPATH)

    def _RestoreChromeEnvironment(self):
        """Restores the Chrome environment to state before the test started."""
        if not self._platform_backend.cri.root_is_writable:
            return
        self._platform_backend.cri.RunCmdOnDevice(
            ['mv', self._EXISTING_ENV_FILEPATH, self._CHROME_ENV_FILEPATH])
Ejemplo n.º 23
0
def CommandToString(command):
  """Returns quoted command that can be run in bash shell."""
  return ' '.join(cmd_helper.SingleQuote(c) for c in command)
Ejemplo n.º 24
0
 def testSingleQuote_withUnsafeChars(self):
     self.assertEquals("""'hello'"'"'; rm -rf /'""",
                       cmd_helper.SingleQuote("hello'; rm -rf /"))
Ejemplo n.º 25
0
 def testSingleQuote_basic(self):
     self.assertEquals('hello', cmd_helper.SingleQuote('hello'))
Ejemplo n.º 26
0
    def PullDumps(self, host_dir):
        """Pulls any minidumps from the device/emulator to the host.

    Skips pulling any dumps that have already been pulled. The modification time
    of any pulled dumps will be set to the modification time of the dump on the
    device/emulator, offset by any difference in clocks between the device and
    host.

    Args:
      host_dir: The directory on the host where the dumps will be copied to.
    """
        # The device/emulator's clock might be off from the host, so calculate an
        # offset that can be added to the host time to get the corresponding device
        # time.
        # The offset is (device_time - host_time), so a positive value means that
        # the device clock is ahead.
        time_offset = self.GetDeviceHostClockOffset()

        stdout, _ = self.RunCmdOnDevice(
            ['ls', '-1',
             cmd_helper.SingleQuote(self.CROS_MINIDUMP_DIR)])
        device_dumps = stdout.splitlines()
        for dump_filename in device_dumps:
            host_path = os.path.join(host_dir, dump_filename)
            # Skip any ignored files since they're not useful and could be deleted by
            # the time we try to pull them.
            if _IsIgnoredFileType(dump_filename):
                continue
            if os.path.exists(host_path):
                continue
            device_path = cmd_helper.SingleQuote(
                posixpath.join(self.CROS_MINIDUMP_DIR, dump_filename))
            # Skip any directories that happen to be in the list.
            stdout, _ = self.RunCmdOnDevice([
                'test', '-f', device_path, '&&', 'echo', 'true', '||', 'echo',
                'false'
            ])
            if 'false' in stdout:
                continue
            # Skip any files that have a corresponding .lock file, as that implies the
            # file hasn't been fully written to disk yet.
            device_lock_path = device_path + '.lock'
            if self.FileExistsOnDevice(device_lock_path):
                logging.debug(
                    'Not pulling file %s because a .lock file exists for it',
                    device_path)
                continue
            try:
                self.GetFile(device_path, host_path)
            except Exception as e:  # pylint: disable=broad-except
                logging.error('Failed to get file %s: %s', device_path, e)
                continue
            # Set the local version's modification time to the device's.
            stdout, _ = self.RunCmdOnDevice(
                ['ls', '--time-style', '+%s', '-l', device_path])
            stdout = stdout.strip()
            # We expect whitespace-separated fields in this order:
            # mode, links, owner, group, size, mtime, filename.
            # Offset by the difference of the device and host clocks.
            device_mtime = int(stdout.split()[5])
            host_mtime = device_mtime - time_offset
            os.utime(host_path, (host_mtime, host_mtime))
Ejemplo n.º 27
0
 def testSingleQuote_withSpaces(self):
     self.assertEquals("'hello world'",
                       cmd_helper.SingleQuote('hello world'))
Ejemplo n.º 28
0
def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.usage = '''%(prog)s --name FILENAME [--device SERIAL] [flags...]

No flags: Prints existing command-line file.
Empty string: Deletes command-line file.
Otherwise: Writes command-line file.

'''
    parser.add_argument(
        '--name',
        required=True,
        help='Name of file where to store flags on the device.')
    parser.add_argument('-e',
                        '--executable',
                        dest='executable',
                        default='chrome',
                        help='(deprecated) No longer used.')
    script_common.AddEnvironmentArguments(parser)
    script_common.AddDeviceArguments(parser)
    logging_common.AddLoggingArguments(parser)

    args, remote_args = parser.parse_known_args()
    script_common.InitializeEnvironment(args)
    logging_common.InitializeLogging(args)

    devices = device_utils.DeviceUtils.HealthyDevices(device_arg=args.devices,
                                                      default_retries=0)
    all_devices = device_utils.DeviceUtils.parallel(devices)

    if not remote_args:
        # No args == do not update, just print flags.
        remote_args = None
        action = ''
    elif len(remote_args) == 1 and not remote_args[0]:
        # Single empty string arg == delete flags
        remote_args = []
        action = 'Deleted command line file. '
    else:
        action = 'Wrote command line file. '

    is_webview = args.name == 'webview-command-line'

    def update_flags(device):
        if device.IsUserBuild() and is_webview:
            raise device_errors.CommandFailedError(
                'WebView only respects flags on a userdebug or eng device, yours '
                'is a user build.', device)
        elif device.IsUserBuild():
            logging.warning(
                'Your device (%s) is a user build; Chrome may or may not pick up '
                'your commandline flags. Check your '
                '"command_line_on_non_rooted_enabled" preference, or switch '
                'devices.', device)
        changer = flag_changer.FlagChanger(device, args.name)
        if remote_args is not None:
            flags = changer.ReplaceFlags(remote_args)
        else:
            flags = changer.GetCurrentFlags()
        return (device, device.build_description, flags)

    updated_values = all_devices.pMap(update_flags).pGet(None)

    print '%sCurrent flags (in %s):' % (action, args.name)
    for d, desc, flags in updated_values:
        if flags:
            # Shell-quote flags for easy copy/paste as new args on the terminal.
            quoted_flags = ' '.join(
                cmd_helper.SingleQuote(f) for f in sorted(flags))
        else:
            quoted_flags = '( empty )'
        print '  %s (%s): %s' % (d, desc, quoted_flags)

    return 0
Ejemplo n.º 29
0
 def testSingleQuote_dontExpand(self):
     test_string = 'hello $TEST_VAR'
     cmd = 'TEST_VAR=world; echo %s' % cmd_helper.SingleQuote(test_string)
     self.assertEquals(test_string,
                       cmd_helper.GetCmdOutput(cmd, shell=True).rstrip())
Ejemplo n.º 30
0
def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.usage = '''%(prog)s --name FILENAME [--device SERIAL] [flags...]

No flags: Prints existing command-line file.
Empty string: Deletes command-line file.
Otherwise: Writes command-line file.

'''
    parser.add_argument('-d',
                        '--device',
                        dest='devices',
                        action='append',
                        default=[],
                        help='Target device serial (repeatable).')
    parser.add_argument(
        '--name',
        required=True,
        help='Name of file where to store flags on the device.')
    parser.add_argument('--device-path',
                        help='(deprecated) No longer needed to'
                        ' supply a device path.')
    parser.add_argument('-e',
                        '--executable',
                        dest='executable',
                        default='chrome',
                        help='(deprecated) No longer used.')
    parser.add_argument('--adb-path',
                        type=os.path.abspath,
                        help='Path to the adb binary.')
    args, remote_args = parser.parse_known_args()

    if args.device_path:
        args.name = posixpath.basename(args.device_path)
        print(
            'warning: --device-path option is deprecated,'
            ' --name %s is now enough.' % cmd_helper.SingleQuote(args.name))

    devil_chromium.Initialize(adb_path=args.adb_path)

    devices = device_utils.DeviceUtils.HealthyDevices(device_arg=args.devices,
                                                      default_retries=0)
    all_devices = device_utils.DeviceUtils.parallel(devices)

    if not remote_args:
        # No args == do not update, just print flags.
        remote_args = None
        action = ''
    elif len(remote_args) == 1 and not remote_args[0]:
        # Single empty string arg == delete flags
        remote_args = []
        action = 'Deleted command line file. '
    else:
        action = 'Wrote command line file. '

    def update_flags(device):
        changer = flag_changer.FlagChanger(device, args.name)
        if remote_args is not None:
            flags = changer.ReplaceFlags(remote_args)
        else:
            flags = changer.GetCurrentFlags()
        return (device, device.build_description, flags)

    updated_values = all_devices.pMap(update_flags).pGet(None)

    print '%sCurrent flags (in %s):' % (action, args.name)
    for d, desc, flags in updated_values:
        if flags:
            # Shell-quote flags for easy copy/paste as new args on the terminal.
            quoted_flags = ' '.join(
                cmd_helper.SingleQuote(f) for f in sorted(flags))
        else:
            quoted_flags = '( empty )'
        print '  %s (%s): %s' % (d, desc, quoted_flags)

    return 0