desktop_browser_finder.py revision 1e9bf3e0803691d0a228da41fc608347b6db4340
1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4"""Finds desktop browsers that can be controlled by telemetry."""
5
6import logging
7import os
8import platform
9import subprocess
10import sys
11
12from telemetry.core import browser
13from telemetry.core import platform as core_platform
14from telemetry.core import possible_browser
15from telemetry.core import util
16from telemetry.core.backends.chrome import cros_interface
17from telemetry.core.backends.chrome import desktop_browser_backend
18
19ALL_BROWSER_TYPES = ','.join([
20    'exact',
21    'release',
22    'release_x64',
23    'debug',
24    'debug_x64',
25    'canary',
26    'content-shell-debug',
27    'content-shell-release',
28    'system'])
29
30class PossibleDesktopBrowser(possible_browser.PossibleBrowser):
31  """A desktop browser that can be controlled."""
32
33  def __init__(self, browser_type, finder_options, executable, flash_path,
34               is_content_shell, browser_directory, is_local_build=False):
35    super(PossibleDesktopBrowser, self).__init__(browser_type, finder_options)
36    self._local_executable = executable
37    self._flash_path = flash_path
38    self._is_content_shell = is_content_shell
39    self._browser_directory = browser_directory
40    self.is_local_build = is_local_build
41
42  def __repr__(self):
43    return 'PossibleDesktopBrowser(browser_type=%s, executable=%s)' % (
44        self.browser_type, self._local_executable)
45
46  def Create(self):
47    backend = desktop_browser_backend.DesktopBrowserBackend(
48        self.finder_options.browser_options, self._local_executable,
49        self._flash_path, self._is_content_shell, self._browser_directory,
50        output_profile_path=self.finder_options.output_profile_path,
51        extensions_to_load=self.finder_options.extensions_to_load)
52    b = browser.Browser(backend,
53                        core_platform.CreatePlatformBackendForCurrentOS())
54    return b
55
56  def SupportsOptions(self, finder_options):
57    if (len(finder_options.extensions_to_load) != 0) and self._is_content_shell:
58      return False
59    return True
60
61  def UpdateExecutableIfNeeded(self):
62    pass
63
64  def last_modification_time(self):
65    if os.path.exists(self._local_executable):
66      return os.path.getmtime(self._local_executable)
67    return -1
68
69def SelectDefaultBrowser(possible_browsers):
70  local_builds_by_date = [
71      b for b in sorted(possible_browsers,
72                        key=lambda b: b.last_modification_time())
73      if b.is_local_build]
74  if local_builds_by_date:
75    return local_builds_by_date[-1]
76  return None
77
78def CanFindAvailableBrowsers():
79  return not cros_interface.IsRunningOnCrosDevice()
80
81def FindAllAvailableBrowsers(finder_options):
82  """Finds all the desktop browsers available on this machine."""
83  browsers = []
84
85  if not CanFindAvailableBrowsers():
86    return []
87
88  has_display = True
89  if (sys.platform.startswith('linux') and
90      os.getenv('DISPLAY') == None):
91    has_display = False
92
93  # Look for a browser in the standard chrome build locations.
94  if finder_options.chrome_root:
95    chrome_root = finder_options.chrome_root
96  else:
97    chrome_root = util.GetChromiumSrcDir()
98
99  chromium_app_names = []
100  if sys.platform == 'darwin':
101    chromium_app_names.append('Chromium.app/Contents/MacOS/Chromium')
102    chromium_app_names.append('Google Chrome.app/Contents/MacOS/Google Chrome')
103    content_shell_app_name = 'Content Shell.app/Contents/MacOS/Content Shell'
104    mac_dir = 'mac'
105    if platform.architecture()[0] == '64bit':
106      mac_dir = 'mac_64'
107    flash_path = os.path.join(
108        chrome_root, 'third_party', 'adobe', 'flash', 'binaries', 'ppapi',
109        mac_dir, 'PepperFlashPlayer.plugin')
110  elif sys.platform.startswith('linux'):
111    chromium_app_names.append('chrome')
112    content_shell_app_name = 'content_shell'
113    linux_dir = 'linux'
114    if platform.architecture()[0] == '64bit':
115      linux_dir = 'linux_x64'
116    flash_path = os.path.join(
117        chrome_root, 'third_party', 'adobe', 'flash', 'binaries', 'ppapi',
118        linux_dir, 'libpepflashplayer.so')
119  elif sys.platform.startswith('win'):
120    chromium_app_names.append('chrome.exe')
121    content_shell_app_name = 'content_shell.exe'
122    win_dir = 'win'
123    if platform.architecture()[0] == '64bit':
124      win_dir = 'win_x64'
125    flash_path = os.path.join(
126        chrome_root, 'third_party', 'adobe', 'flash', 'binaries', 'ppapi',
127        win_dir, 'pepflashplayer.dll')
128  else:
129    raise Exception('Platform not recognized')
130
131  def IsExecutable(path):
132    return os.path.isfile(path) and os.access(path, os.X_OK)
133
134  # Add the explicit browser executable if given.
135  if finder_options.browser_executable:
136    normalized_executable = os.path.expanduser(
137        finder_options.browser_executable)
138    if IsExecutable(normalized_executable):
139      browser_directory = os.path.dirname(finder_options.browser_executable)
140      browsers.append(PossibleDesktopBrowser('exact', finder_options,
141                                             normalized_executable, flash_path,
142                                             False, browser_directory))
143    else:
144      logging.warning('%s specified by browser_executable does not exist',
145                      normalized_executable)
146
147  def AddIfFound(browser_type, build_dir, type_dir, app_name, content_shell):
148    browser_directory = os.path.join(chrome_root, build_dir, type_dir)
149    app = os.path.join(browser_directory, app_name)
150    if IsExecutable(app):
151      browsers.append(PossibleDesktopBrowser(browser_type, finder_options,
152                                             app, flash_path, content_shell,
153                                             browser_directory,
154                                             is_local_build=True))
155      return True
156    return False
157
158  # Add local builds
159  for build_dir, build_type in util.GetBuildDirectories():
160    for chromium_app_name in chromium_app_names:
161      AddIfFound(build_type.lower(), build_dir, build_type,
162                 chromium_app_name, False)
163    AddIfFound('content-shell-' + build_type.lower(), build_dir, build_type,
164               content_shell_app_name, True)
165
166  # Mac-specific options.
167  if sys.platform == 'darwin':
168    mac_canary_root = '/Applications/Google Chrome Canary.app/'
169    mac_canary = mac_canary_root + 'Contents/MacOS/Google Chrome Canary'
170    mac_system_root = '/Applications/Google Chrome.app'
171    mac_system = mac_system_root + '/Contents/MacOS/Google Chrome'
172    if IsExecutable(mac_canary):
173      browsers.append(PossibleDesktopBrowser('canary', finder_options,
174                                             mac_canary, None, False,
175                                             mac_canary_root))
176
177    if IsExecutable(mac_system):
178      browsers.append(PossibleDesktopBrowser('system', finder_options,
179                                             mac_system, None, False,
180                                             mac_system_root))
181
182  # Linux specific options.
183  if sys.platform.startswith('linux'):
184    # Look for a google-chrome instance.
185    found = False
186    try:
187      with open(os.devnull, 'w') as devnull:
188        found = subprocess.call(['google-chrome', '--version'],
189                                stdout=devnull, stderr=devnull) == 0
190    except OSError:
191      pass
192    if found:
193      browsers.append(PossibleDesktopBrowser('system', finder_options,
194                                             'google-chrome', None, False,
195                                             '/opt/google/chrome'))
196
197  # Win32-specific options.
198  if sys.platform.startswith('win'):
199    system_path = os.path.join('Google', 'Chrome', 'Application')
200    canary_path = os.path.join('Google', 'Chrome SxS', 'Application')
201
202    win_search_paths = [os.getenv('PROGRAMFILES(X86)'),
203                        os.getenv('PROGRAMFILES'),
204                        os.getenv('LOCALAPPDATA')]
205
206    def AddIfFoundWin(browser_name, app_path):
207      browser_directory = os.path.join(path, app_path)
208      for chromium_app_name in chromium_app_names:
209        app = os.path.join(browser_directory, chromium_app_name)
210        if IsExecutable(app):
211          browsers.append(PossibleDesktopBrowser(browser_name, finder_options,
212                                                 app, flash_path, False,
213                                                 browser_directory))
214        return True
215      return False
216
217    for path in win_search_paths:
218      if not path:
219        continue
220      if AddIfFoundWin('canary', canary_path):
221        break
222
223    for path in win_search_paths:
224      if not path:
225        continue
226      if AddIfFoundWin('system', system_path):
227        break
228
229  if len(browsers) and not has_display:
230    logging.warning(
231      'Found (%s), but you do not have a DISPLAY environment set.' %
232      ','.join([b.browser_type for b in browsers]))
233    return []
234
235  return browsers
236