1a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import contextlib
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import httplib
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import json
88bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import logging
98bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import pprint
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import re
11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import socket
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import sys
13a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import urllib2
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from telemetry import decorators
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import exceptions
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core import forwarders
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import user_agent
19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core import util
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochfrom telemetry.core import web_contents
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import wpr_modes
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import wpr_server
23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core.backends import browser_backend
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from telemetry.core.backends.chrome import extension_backend
25424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends.chrome import system_info_backend
26424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends.chrome import tab_list_backend
27424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends.chrome import tracing_backend
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)from telemetry.timeline import tracing_timeline_data
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)from telemetry.unittest import options_for_unittests
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class ChromeBrowserBackend(browser_backend.BrowserBackend):
33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  """An abstract class for chrome browser backends. Provides basic functionality
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  once a remote-debugger port has been established."""
35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  # It is OK to have abstract methods. pylint: disable=W0223
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def __init__(self, supports_tab_control, supports_extensions, browser_options,
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)               output_profile_path, extensions_to_load):
39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    super(ChromeBrowserBackend, self).__init__(
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        supports_extensions=supports_extensions,
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        browser_options=browser_options,
42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        tab_list_backend=tab_list_backend.TabListBackend)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._port = None
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._supports_tab_control = supports_tab_control
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._tracing_backend = None
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._system_info_backend = None
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self._output_profile_path = output_profile_path
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self._extensions_to_load = extensions_to_load
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if browser_options.netsim:
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.wpr_port_pairs = forwarders.PortPairs(
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          http=forwarders.PortPair(80, 80),
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          https=forwarders.PortPair(443, 443),
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          dns=forwarders.PortPair(53, 53))
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    else:
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.wpr_port_pairs = forwarders.PortPairs(
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          http=forwarders.PortPair(0, 0),
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          https=forwarders.PortPair(0, 0),
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          dns=None)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (self.browser_options.dont_override_profile and
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        not options_for_unittests.AreSet()):
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sys.stderr.write('Warning: Not overriding profile. This can cause '
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       'unexpected effects due to profile-specific settings, '
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       'such as about:flags settings, cookies, and '
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       'extensions.\n')
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def AddReplayServerOptions(self, extra_wpr_args):
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if self.browser_options.netsim:
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extra_wpr_args.append('--net=%s' % self.browser_options.netsim)
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    else:
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extra_wpr_args.append('--no-dns_forwarding')
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @decorators.Cache
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def extension_backend(self):
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if not self.supports_extensions:
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return None
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return extension_backend.ExtensionBackendDict(self)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetBrowserStartupArgs(self):
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args = []
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    args.extend(self.browser_options.extra_browser_args)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    args.append('--enable-net-benchmarking')
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.append('--metrics-recording-only')
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    args.append('--no-default-browser-check')
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    args.append('--no-first-run')
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # Turn on GPU benchmarking extension for all runs. The only side effect of
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # the extension being on is that render stats are tracked. This is believed
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # to be effectively free. And, by doing so here, it avoids us having to
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # programmatically inspect a pageset's actions in order to determine if it
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # might eventually scroll.
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    args.append('--enable-gpu-benchmarking')
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # Set --no-proxy-server to work around some XP issues unless
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # some other flag indicates a proxy is needed.
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if not '--enable-spdy-proxy-auth' in args:
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      args.append('--no-proxy-server')
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if self.browser_options.disable_background_networking:
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      args.append('--disable-background-networking')
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if self.browser_options.netsim:
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      args.append('--ignore-certificate-errors')
108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    elif self.browser_options.wpr_mode != wpr_modes.WPR_OFF:
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      args.extend(wpr_server.GetChromeFlags(self.forwarder_factory.host_ip,
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            self.wpr_port_pairs))
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.extend(user_agent.GetChromeUserAgentArgumentFromType(
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        self.browser_options.browser_user_agent_type))
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    extensions = [extension.local_path
11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                  for extension in self._extensions_to_load
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                  if not extension.is_component]
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    extension_str = ','.join(extensions)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if len(extensions) > 0:
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      args.append('--load-extension=%s' % extension_str)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    component_extensions = [extension.local_path
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            for extension in self._extensions_to_load
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            if extension.is_component]
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    component_extension_str = ','.join(component_extensions)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if len(component_extensions) > 0:
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      args.append('--load-component-extension=%s' % component_extension_str)
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if self.browser_options.no_proxy_server:
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      args.append('--no-proxy-server')
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if self.browser_options.disable_component_extensions_with_background_pages:
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      args.append('--disable-component-extensions-with-background-pages')
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return args
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def HasBrowserFinishedLaunching(self):
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    try:
13803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      self.Request('', timeout=.1)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    except (exceptions.BrowserGoneException,
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            exceptions.BrowserConnectionGoneException):
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return False
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return True
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def _WaitForBrowserToComeUp(self, wait_for_extensions=True):
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    try:
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      util.WaitFor(self.HasBrowserFinishedLaunching, timeout=30)
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    except (util.TimeoutException, exceptions.ProcessGoneException) as e:
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if not self.IsBrowserRunning():
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        raise exceptions.BrowserGoneException(self.browser, e)
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      raise exceptions.BrowserConnectionGoneException(self.browser, e)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def AllExtensionsLoaded():
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # Extension pages are loaded from an about:blank page,
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # so we need to check that the document URL is the extension
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # page in addition to the ready state.
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      extension_ready_js = """
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          document.URL.lastIndexOf('chrome-extension://%s/', 0) == 0 &&
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          (document.readyState == 'complete' ||
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)           document.readyState == 'interactive')
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      """
16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      for e in self._extensions_to_load:
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        try:
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          extension_objects = self.extension_backend[e.extension_id]
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        except KeyError:
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return False
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        for extension_object in extension_objects:
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          try:
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            res = extension_object.EvaluateJavaScript(
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                extension_ready_js % e.extension_id)
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          except exceptions.EvaluateException:
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            # If the inspected page is not ready, we will get an error
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            # when we evaluate a JS expression, but we can just keep polling
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            # until the page is ready (crbug.com/251913).
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            res = None
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          # TODO(tengs): We don't have full support for getting the Chrome
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          # version before launch, so for now we use a generic workaround to
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          # check for an extension binding bug in old versions of Chrome.
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          # See crbug.com/263162 for details.
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if res and extension_object.EvaluateJavaScript(
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              'chrome.runtime == null'):
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            extension_object.Reload()
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if not res:
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            return False
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return True
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
18858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if wait_for_extensions and self._supports_extensions:
1898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      try:
1908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        util.WaitFor(AllExtensionsLoaded, timeout=60)
1918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      except util.TimeoutException:
1928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        logging.error('ExtensionsToLoad: ' +
1938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            repr([e.extension_id for e in self._extensions_to_load]))
1948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        logging.error('Extension list: ' +
195a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch            pprint.pformat(self.extension_backend, indent=4))
1968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        raise
1978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def ListInspectableContexts(self):
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return json.loads(self.Request(''))
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
20103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  def Request(self, path, timeout=30, throw_network_exception=False):
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    url = 'http://127.0.0.1:%i/json' % self._port
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if path:
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      url += '/' + path
205558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    try:
2063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      proxy_handler = urllib2.ProxyHandler({})  # Bypass any system proxy.
2073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      opener = urllib2.build_opener(proxy_handler)
2086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      with contextlib.closing(opener.open(url, timeout=timeout)) as req:
2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return req.read()
210558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    except (socket.error, httplib.BadStatusLine, urllib2.URLError) as e:
211558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      if throw_network_exception:
212558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        raise e
213558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      if not self.IsBrowserRunning():
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        raise exceptions.BrowserGoneException(self.browser, e)
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      raise exceptions.BrowserConnectionGoneException(self.browser, e)
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
218bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def browser_directory(self):
219bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    raise NotImplementedError()
220bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
221bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  @property
222bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def profile_directory(self):
223bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    raise NotImplementedError()
224bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
225bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  @property
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  @decorators.Cache
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def chrome_branch_number(self):
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # Detect version information.
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    data = self.Request('version')
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    resp = json.loads(data)
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if 'Protocol-Version' in resp:
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if 'Browser' in resp:
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        branch_number_match = re.search('Chrome/\d+\.\d+\.(\d+)\.\d+',
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        resp['Browser'])
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      else:
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        branch_number_match = re.search(
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            'Chrome/\d+\.\d+\.(\d+)\.\d+ (Mobile )?Safari',
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            resp['User-Agent'])
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if branch_number_match:
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        branch_number = int(branch_number_match.group(1))
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if branch_number:
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          return branch_number
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # Branch number can't be determined, so fail any branch number checks.
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return 0
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def supports_tab_control(self):
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return self._supports_tab_control
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def supports_tracing(self):
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return True
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  def StartTracing(self, trace_options, custom_categories=None,
257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                   timeout=web_contents.DEFAULT_WEB_CONTENTS_TIMEOUT):
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    """
2596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Args:
2606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        trace_options: An tracing_options.TracingOptions instance.
2616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        custom_categories: An optional string containing a list of
2626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                         comma separated categories that will be traced
2636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                         instead of the default category set.  Example: use
2646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                         "webkit,cc,disabled-by-default-cc.debug" to trace only
2656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                         those three event categories.
2666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    """
2676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    assert trace_options and trace_options.enable_chrome_trace
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._tracing_backend is None:
2696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      self._tracing_backend = tracing_backend.TracingBackend(self._port, self)
2706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return self._tracing_backend.StartTracing(
2716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        trace_options, custom_categories, timeout)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @property
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def is_tracing_running(self):
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if not self._tracing_backend:
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return None
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return self._tracing_backend.is_tracing_running
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def StopTracing(self):
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """ Stops tracing and returns the result as TimelineData object. """
281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    tab_ids_list = []
282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for (i, _) in enumerate(self._browser.tabs):
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      tab = self.tab_list_backend.Get(i, None)
284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if tab:
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        success = tab.EvaluateJavaScript(
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            "console.time('" + tab.id + "');" +
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            "console.timeEnd('" + tab.id + "');" +
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            "console.time.toString().indexOf('[native code]') != -1;")
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if not success:
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          raise Exception('Page stomped on console.time')
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        tab_ids_list.append(tab.id)
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    trace_events = self._tracing_backend.StopTracing()
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    # Augment tab_ids data to trace events.
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    event_data = {'traceEvents' : trace_events, 'tabIds': tab_ids_list}
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return tracing_timeline_data.TracingTimelineData(event_data)
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
297b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def GetProcessName(self, cmd_line):
298b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    """Returns a user-friendly name for the process of the given |cmd_line|."""
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if not cmd_line:
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # TODO(tonyg): Eventually we should make all of these known and add an
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # assertion.
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return 'unknown'
303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if 'nacl_helper_bootstrap' in cmd_line:
304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return 'nacl_helper_bootstrap'
305a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if ':sandboxed_process' in cmd_line:
306a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return 'renderer'
307b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    m = re.match(r'.* --type=([^\s]*) .*', cmd_line)
308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if not m:
309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return 'browser'
310b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return m.group(1)
311b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Close(self):
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._tracing_backend:
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._tracing_backend.Close()
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._tracing_backend = None
3163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  @property
3183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def supports_system_info(self):
3193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self.GetSystemInfo() != None
3203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def GetSystemInfo(self):
3223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if self._system_info_backend is None:
3233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      self._system_info_backend = system_info_backend.SystemInfoBackend(
3243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          self._port)
3253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self._system_info_backend.GetSystemInfo()
326