chrome_browser_backend.py revision 58537e28ecd584eab876aee8be7156509866d23a
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)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import httplib
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import json
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import re
8a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import socket
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import sys
10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import urllib2
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import exceptions
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import user_agent
14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core import util
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochfrom telemetry.core import web_contents
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import wpr_modes
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import wpr_server
18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core.backends import browser_backend
19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends.chrome import extension_dict_backend
20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends.chrome import misc_web_contents_backend
21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends.chrome import system_info_backend
22424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends.chrome import tab_list_backend
23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends.chrome import tracing_backend
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)from telemetry.unittest import options_for_unittests
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class ChromeBrowserBackend(browser_backend.BrowserBackend):
27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  """An abstract class for chrome browser backends. Provides basic functionality
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  once a remote-debugger port has been established."""
29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  # It is OK to have abstract methods. pylint: disable=W0223
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def __init__(self, is_content_shell, supports_extensions, browser_options,
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)               output_profile_path, extensions_to_load):
33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    super(ChromeBrowserBackend, self).__init__(
34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        is_content_shell=is_content_shell,
35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        supports_extensions=supports_extensions,
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        browser_options=browser_options,
37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        tab_list_backend=tab_list_backend.TabListBackend)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._port = None
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._inspector_protocol_version = 0
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._chrome_branch_number = None
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._tracing_backend = None
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._system_info_backend = None
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self._output_profile_path = output_profile_path
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self._extensions_to_load = extensions_to_load
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.webpagereplay_local_http_port = util.GetAvailableLocalPort()
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.webpagereplay_local_https_port = util.GetAvailableLocalPort()
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.webpagereplay_remote_http_port = self.webpagereplay_local_http_port
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.webpagereplay_remote_https_port = self.webpagereplay_local_https_port
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (self.browser_options.dont_override_profile and
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        not options_for_unittests.AreSet()):
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sys.stderr.write('Warning: Not overriding profile. This can cause '
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       'unexpected effects due to profile-specific settings, '
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       'such as about:flags settings, cookies, and '
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       'extensions.\n')
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self._misc_web_contents_backend = (
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        misc_web_contents_backend.MiscWebContentsBackend(self))
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._extension_dict_backend = None
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if supports_extensions:
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self._extension_dict_backend = (
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          extension_dict_backend.ExtensionDictBackend(self))
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def AddReplayServerOptions(self, extra_wpr_args):
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    extra_wpr_args.append('--no-dns_forwarding')
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def misc_web_contents_backend(self):
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    """Access to chrome://oobe/login page which is neither a tab nor an
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    extension."""
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return self._misc_web_contents_backend
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  @property
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def extension_dict_backend(self):
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self._extension_dict_backend
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetBrowserStartupArgs(self):
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args = []
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    args.extend(self.browser_options.extra_browser_args)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.append('--disable-background-networking')
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.append('--metrics-recording-only')
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.append('--no-first-run')
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    args.append('--no-proxy-server')
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if self.browser_options.wpr_mode != wpr_modes.WPR_OFF:
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      args.extend(wpr_server.GetChromeFlags(
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          self.WEBPAGEREPLAY_HOST,
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          self.webpagereplay_remote_http_port,
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          self.webpagereplay_remote_https_port))
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.extend(user_agent.GetChromeUserAgentArgumentFromType(
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        self.browser_options.browser_user_agent_type))
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    extensions = [extension.local_path
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                  for extension in self._extensions_to_load
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                  if not extension.is_component]
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    extension_str = ','.join(extensions)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if len(extensions) > 0:
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      args.append('--load-extension=%s' % extension_str)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    component_extensions = [extension.local_path
10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            for extension in self._extensions_to_load
10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            if extension.is_component]
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    component_extension_str = ','.join(component_extensions)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if len(component_extensions) > 0:
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      args.append('--load-component-extension=%s' % component_extension_str)
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if self.browser_options.no_proxy_server:
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      args.append('--no-proxy-server')
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return args
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def _WaitForBrowserToComeUp(self, wait_for_extensions=True, timeout=None):
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def IsBrowserUp():
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      try:
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.Request('', timeout=timeout)
117558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      except (exceptions.BrowserGoneException,
118558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch              exceptions.BrowserConnectionGoneException):
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return False
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return True
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    try:
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      util.WaitFor(IsBrowserUp, timeout=30)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    except util.TimeoutException:
125ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      raise exceptions.BrowserGoneException(self.GetStackTrace())
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def AllExtensionsLoaded():
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # Extension pages are loaded from an about:blank page,
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # so we need to check that the document URL is the extension
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      # page in addition to the ready state.
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      extension_ready_js = """
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          document.URL.lastIndexOf('chrome-extension://%s/', 0) == 0 &&
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          (document.readyState == 'complete' ||
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)           document.readyState == 'interactive')
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      """
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      for e in self._extensions_to_load:
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if not e.extension_id in self._extension_dict_backend:
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return False
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        extension_object = self._extension_dict_backend[e.extension_id]
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        res = extension_object.EvaluateJavaScript(
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            extension_ready_js % e.extension_id)
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if not res:
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          return False
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return True
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if wait_for_extensions and self._supports_extensions:
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      util.WaitFor(AllExtensionsLoaded, timeout=30)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _PostBrowserStartupInitialization(self):
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Detect version information.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    data = self.Request('version')
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resp = json.loads(data)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if 'Protocol-Version' in resp:
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._inspector_protocol_version = resp['Protocol-Version']
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if self._chrome_branch_number:
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if 'Browser' in resp:
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        branch_number_match = re.search('Chrome/\d+\.\d+\.(\d+)\.\d+',
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        resp['Browser'])
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        branch_number_match = re.search(
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            'Chrome/\d+\.\d+\.(\d+)\.\d+ (Mobile )?Safari',
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            resp['User-Agent'])
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if branch_number_match:
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._chrome_branch_number = int(branch_number_match.group(1))
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # Content Shell returns '' for Browser, for now we have to
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # fall-back and assume branch 1025.
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._chrome_branch_number = 1025
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Detection has failed: assume 18.0.1025.168 ~= Chrome Android.
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._inspector_protocol_version = 1.0
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._chrome_branch_number = 1025
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
178558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  def Request(self, path, timeout=None, throw_network_exception=False):
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url = 'http://localhost:%i/json' % self._port
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if path:
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      url += '/' + path
182558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    try:
1833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      proxy_handler = urllib2.ProxyHandler({})  # Bypass any system proxy.
1843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      opener = urllib2.build_opener(proxy_handler)
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      req = opener.open(url, timeout=timeout)
186558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      return req.read()
187558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    except (socket.error, httplib.BadStatusLine, urllib2.URLError) as e:
188558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      if throw_network_exception:
189558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        raise e
190558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      if not self.IsBrowserRunning():
191558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        raise exceptions.BrowserGoneException()
192558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      raise exceptions.BrowserConnectionGoneException()
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
195bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def browser_directory(self):
196bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    raise NotImplementedError()
197bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
198bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  @property
199bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def profile_directory(self):
200bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    raise NotImplementedError()
201bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
202bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  @property
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def chrome_branch_number(self):
2043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    assert self._chrome_branch_number
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self._chrome_branch_number
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def supports_tab_control(self):
2093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self.chrome_branch_number >= 1303
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def supports_tracing(self):
2133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self.is_content_shell or self.chrome_branch_number >= 1385
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  def StartTracing(self, custom_categories=None,
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                   timeout=web_contents.DEFAULT_WEB_CONTENTS_TIMEOUT):
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    """ custom_categories is an optional string containing a list of
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    comma separated categories that will be traced instead of the
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    default category set.  Example: use
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    "webkit,cc,disabled-by-default-cc.debug" to trace only those three
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    event categories.
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    """
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._tracing_backend is None:
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._tracing_backend = tracing_backend.TracingBackend(self._port)
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    self._tracing_backend.BeginTracing(custom_categories, timeout)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def StopTracing(self):
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._tracing_backend.EndTracing()
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetTraceResultAndReset(self):
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self._tracing_backend.GetTraceResultAndReset()
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
233b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def GetProcessName(self, cmd_line):
234b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    """Returns a user-friendly name for the process of the given |cmd_line|."""
235b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if 'nacl_helper_bootstrap' in cmd_line:
236b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return 'nacl_helper_bootstrap'
237a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if ':sandboxed_process' in cmd_line:
238a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return 'renderer'
239b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    m = re.match(r'.* --type=([^\s]*) .*', cmd_line)
240b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if not m:
241b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return 'browser'
242b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return m.group(1)
243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Close(self):
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._tracing_backend:
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._tracing_backend.Close()
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._tracing_backend = None
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if self._system_info_backend:
2493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      self._system_info_backend.Close()
2503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      self._system_info_backend = None
2513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  @property
2533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def supports_system_info(self):
2543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self.GetSystemInfo() != None
2553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def GetSystemInfo(self):
2573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if self._system_info_backend is None:
2583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      self._system_info_backend = system_info_backend.SystemInfoBackend(
2593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          self._port)
2603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self._system_info_backend.GetSystemInfo()
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def _SetBranchNumber(self, version):
2633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    assert version
2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._chrome_branch_number = re.search(r'\d+\.\d+\.(\d+)\.\d+',
2653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                           version).group(1)
266