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 sys 9 10import dependency_manager # pylint: disable=import-error 11 12from telemetry.core import exceptions 13from telemetry.core import platform as platform_module 14from telemetry.internal.backends.chrome import desktop_browser_backend 15from telemetry.internal.browser import browser 16from telemetry.internal.browser import possible_browser 17from telemetry.internal.platform import desktop_device 18from telemetry.internal.util import binary_manager 19# This is a workaround for https://goo.gl/1tGNgd 20from telemetry.internal.util import path as path_module 21 22 23class PossibleDesktopBrowser(possible_browser.PossibleBrowser): 24 """A desktop browser that can be controlled.""" 25 26 def __init__(self, browser_type, finder_options, executable, flash_path, 27 is_content_shell, browser_directory, is_local_build=False): 28 target_os = sys.platform.lower() 29 super(PossibleDesktopBrowser, self).__init__( 30 browser_type, target_os, not is_content_shell) 31 assert browser_type in FindAllBrowserTypes(finder_options), ( 32 'Please add %s to desktop_browser_finder.FindAllBrowserTypes' % 33 browser_type) 34 self._local_executable = executable 35 self._flash_path = flash_path 36 self._is_content_shell = is_content_shell 37 self._browser_directory = browser_directory 38 self.is_local_build = is_local_build 39 40 def __repr__(self): 41 return 'PossibleDesktopBrowser(type=%s, executable=%s, flash=%s)' % ( 42 self.browser_type, self._local_executable, self._flash_path) 43 44 def _InitPlatformIfNeeded(self): 45 if self._platform: 46 return 47 48 self._platform = platform_module.GetHostPlatform() 49 50 # pylint: disable=protected-access 51 self._platform_backend = self._platform._platform_backend 52 53 def Create(self, finder_options): 54 if self._flash_path and not os.path.exists(self._flash_path): 55 logging.warning( 56 'Could not find Flash at %s. Continuing without Flash.\n' 57 'To run with Flash, check it out via http://go/read-src-internal', 58 self._flash_path) 59 self._flash_path = None 60 61 self._InitPlatformIfNeeded() 62 63 browser_backend = desktop_browser_backend.DesktopBrowserBackend( 64 self._platform_backend, 65 finder_options.browser_options, self._local_executable, 66 self._flash_path, self._is_content_shell, self._browser_directory, 67 output_profile_path=finder_options.output_profile_path, 68 extensions_to_load=finder_options.extensions_to_load) 69 return browser.Browser( 70 browser_backend, self._platform_backend, self._credentials_path) 71 72 def SupportsOptions(self, finder_options): 73 if (len(finder_options.extensions_to_load) != 0) and self._is_content_shell: 74 return False 75 return True 76 77 def UpdateExecutableIfNeeded(self): 78 pass 79 80 def last_modification_time(self): 81 if os.path.exists(self._local_executable): 82 return os.path.getmtime(self._local_executable) 83 return -1 84 85def SelectDefaultBrowser(possible_browsers): 86 local_builds_by_date = [ 87 b for b in sorted(possible_browsers, 88 key=lambda b: b.last_modification_time()) 89 if b.is_local_build] 90 if local_builds_by_date: 91 return local_builds_by_date[-1] 92 return None 93 94def CanFindAvailableBrowsers(): 95 return not platform_module.GetHostPlatform().GetOSName() == 'chromeos' 96 97def CanPossiblyHandlePath(target_path): 98 _, extension = os.path.splitext(target_path.lower()) 99 if sys.platform == 'darwin' or sys.platform.startswith('linux'): 100 return not extension 101 elif sys.platform.startswith('win'): 102 return extension == '.exe' 103 return False 104 105def FindAllBrowserTypes(_): 106 return [ 107 'exact', 108 'reference', 109 'release', 110 'release_x64', 111 'debug', 112 'debug_x64', 113 'default', 114 'stable', 115 'beta', 116 'dev', 117 'canary', 118 'content-shell-debug', 119 'content-shell-debug_x64', 120 'content-shell-release', 121 'content-shell-release_x64', 122 'content-shell-default', 123 'system'] 124 125def FindAllAvailableBrowsers(finder_options, device): 126 """Finds all the desktop browsers available on this machine.""" 127 if not isinstance(device, desktop_device.DesktopDevice): 128 return [] 129 130 browsers = [] 131 132 if not CanFindAvailableBrowsers(): 133 return [] 134 135 has_x11_display = True 136 if (sys.platform.startswith('linux') and 137 os.getenv('DISPLAY') == None): 138 has_x11_display = False 139 140 os_name = platform_module.GetHostPlatform().GetOSName() 141 arch_name = platform_module.GetHostPlatform().GetArchName() 142 try: 143 flash_path = binary_manager.LocalPath('flash', arch_name, os_name) 144 except dependency_manager.NoPathFoundError: 145 flash_path = None 146 logging.warning( 147 'Chrome build location for %s_%s not found. Browser will be run ' 148 'without Flash.', os_name, arch_name) 149 150 chromium_app_names = [] 151 if sys.platform == 'darwin': 152 chromium_app_names.append('Chromium.app/Contents/MacOS/Chromium') 153 chromium_app_names.append('Google Chrome.app/Contents/MacOS/Google Chrome') 154 content_shell_app_name = 'Content Shell.app/Contents/MacOS/Content Shell' 155 elif sys.platform.startswith('linux'): 156 chromium_app_names.append('chrome') 157 content_shell_app_name = 'content_shell' 158 elif sys.platform.startswith('win'): 159 chromium_app_names.append('chrome.exe') 160 content_shell_app_name = 'content_shell.exe' 161 else: 162 raise Exception('Platform not recognized') 163 164 # Add the explicit browser executable if given and we can handle it. 165 if (finder_options.browser_executable and 166 CanPossiblyHandlePath(finder_options.browser_executable)): 167 is_content_shell = finder_options.browser_executable.endswith( 168 content_shell_app_name) 169 is_chrome_or_chromium = len([x for x in chromium_app_names if 170 finder_options.browser_executable.endswith(x)]) != 0 171 172 # It is okay if the executable name doesn't match any of known chrome 173 # browser executables, since it may be of a different browser. 174 if is_chrome_or_chromium or is_content_shell: 175 normalized_executable = os.path.expanduser( 176 finder_options.browser_executable) 177 if path_module.IsExecutable(normalized_executable): 178 browser_directory = os.path.dirname(finder_options.browser_executable) 179 browsers.append(PossibleDesktopBrowser( 180 'exact', finder_options, normalized_executable, flash_path, 181 is_content_shell, 182 browser_directory)) 183 else: 184 raise exceptions.PathMissingError( 185 '%s specified by --browser-executable does not exist or is not ' 186 'executable' % 187 normalized_executable) 188 189 def AddIfFound(browser_type, build_path, app_name, content_shell): 190 app = os.path.join(build_path, app_name) 191 if path_module.IsExecutable(app): 192 browsers.append(PossibleDesktopBrowser( 193 browser_type, finder_options, app, flash_path, 194 content_shell, build_path, is_local_build=True)) 195 return True 196 return False 197 198 # Add local builds 199 for build_path in path_module.GetBuildDirectories(finder_options.chrome_root): 200 # TODO(agrieve): Extract browser_type from args.gn's is_debug. 201 browser_type = os.path.basename(build_path).lower() 202 for chromium_app_name in chromium_app_names: 203 AddIfFound(browser_type, build_path, chromium_app_name, False) 204 AddIfFound('content-shell-' + browser_type, build_path, 205 content_shell_app_name, True) 206 207 reference_build = None 208 if finder_options.browser_type == 'reference': 209 # Reference builds are only available in a Chromium checkout. We should not 210 # raise an error just because they don't exist. 211 os_name = platform_module.GetHostPlatform().GetOSName() 212 arch_name = platform_module.GetHostPlatform().GetArchName() 213 reference_build = binary_manager.FetchPath( 214 'reference_build', arch_name, os_name) 215 216 # Mac-specific options. 217 if sys.platform == 'darwin': 218 mac_canary_root = '/Applications/Google Chrome Canary.app/' 219 mac_canary = mac_canary_root + 'Contents/MacOS/Google Chrome Canary' 220 mac_system_root = '/Applications/Google Chrome.app' 221 mac_system = mac_system_root + '/Contents/MacOS/Google Chrome' 222 if path_module.IsExecutable(mac_canary): 223 browsers.append(PossibleDesktopBrowser('canary', finder_options, 224 mac_canary, None, False, 225 mac_canary_root)) 226 227 if path_module.IsExecutable(mac_system): 228 browsers.append(PossibleDesktopBrowser('system', finder_options, 229 mac_system, None, False, 230 mac_system_root)) 231 232 if reference_build and path_module.IsExecutable(reference_build): 233 reference_root = os.path.dirname(os.path.dirname(os.path.dirname( 234 reference_build))) 235 browsers.append(PossibleDesktopBrowser('reference', finder_options, 236 reference_build, None, False, 237 reference_root)) 238 239 # Linux specific options. 240 if sys.platform.startswith('linux'): 241 versions = { 242 'system': os.path.split(os.path.realpath('/usr/bin/google-chrome'))[0], 243 'stable': '/opt/google/chrome', 244 'beta': '/opt/google/chrome-beta', 245 'dev': '/opt/google/chrome-unstable' 246 } 247 248 for version, root in versions.iteritems(): 249 browser_path = os.path.join(root, 'chrome') 250 if path_module.IsExecutable(browser_path): 251 browsers.append(PossibleDesktopBrowser(version, finder_options, 252 browser_path, None, False, root)) 253 if reference_build and path_module.IsExecutable(reference_build): 254 reference_root = os.path.dirname(reference_build) 255 browsers.append(PossibleDesktopBrowser('reference', finder_options, 256 reference_build, None, False, 257 reference_root)) 258 259 # Win32-specific options. 260 if sys.platform.startswith('win'): 261 app_paths = [ 262 ('system', os.path.join('Google', 'Chrome', 'Application')), 263 ('canary', os.path.join('Google', 'Chrome SxS', 'Application')), 264 ] 265 if reference_build: 266 app_paths.append( 267 ('reference', os.path.dirname(reference_build))) 268 269 for browser_name, app_path in app_paths: 270 for chromium_app_name in chromium_app_names: 271 full_path = path_module.FindInstalledWindowsApplication( 272 os.path.join(app_path, chromium_app_name)) 273 if full_path: 274 browsers.append(PossibleDesktopBrowser( 275 browser_name, finder_options, full_path, 276 None, False, os.path.dirname(full_path))) 277 278 has_ozone_platform = False 279 for arg in finder_options.browser_options.extra_browser_args: 280 if "--ozone-platform" in arg: 281 has_ozone_platform = True 282 283 if len(browsers) and not has_x11_display and not has_ozone_platform: 284 logging.warning( 285 'Found (%s), but you do not have a DISPLAY environment set.' % 286 ','.join([b.browser_type for b in browsers])) 287 return [] 288 289 return browsers 290