1# Copyright 2012 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 5"""Finds browsers that can be controlled by telemetry.""" 6 7import logging 8import operator 9 10from telemetry import decorators 11from telemetry.internal.backends.chrome import android_browser_finder 12from telemetry.internal.backends.chrome import cros_browser_finder 13from telemetry.internal.backends.chrome import desktop_browser_finder 14from telemetry.internal.backends.chrome import ios_browser_finder 15from telemetry.internal.browser import browser_finder_exceptions 16from telemetry.internal.platform import device_finder 17 18BROWSER_FINDERS = [ 19 desktop_browser_finder, 20 android_browser_finder, 21 cros_browser_finder, 22 ios_browser_finder, 23 ] 24 25 26def FindAllBrowserTypes(options): 27 return reduce(operator.add, 28 [bf.FindAllBrowserTypes(options) for bf in BROWSER_FINDERS]) 29 30 31@decorators.Cache 32def FindBrowser(options): 33 """Finds the best PossibleBrowser object given a BrowserOptions object. 34 35 Args: 36 A BrowserOptions object. 37 38 Returns: 39 A PossibleBrowser object. 40 41 Raises: 42 BrowserFinderException: Options improperly set, or an error occurred. 43 """ 44 if options.__class__.__name__ == '_FakeBrowserFinderOptions': 45 return options.fake_possible_browser 46 if options.browser_type == 'exact' and options.browser_executable == None: 47 raise browser_finder_exceptions.BrowserFinderException( 48 '--browser=exact requires --browser-executable to be set.') 49 if options.browser_type != 'exact' and options.browser_executable != None: 50 raise browser_finder_exceptions.BrowserFinderException( 51 '--browser-executable requires --browser=exact.') 52 53 if options.browser_type == 'cros-chrome' and options.cros_remote == None: 54 raise browser_finder_exceptions.BrowserFinderException( 55 'browser_type=cros-chrome requires cros_remote be set.') 56 if (options.browser_type != 'cros-chrome' and 57 options.browser_type != 'cros-chrome-guest' and 58 options.cros_remote != None): 59 raise browser_finder_exceptions.BrowserFinderException( 60 '--remote requires --browser=cros-chrome or cros-chrome-guest.') 61 62 devices = device_finder.GetDevicesMatchingOptions(options) 63 browsers = [] 64 default_browsers = [] 65 for device in devices: 66 for finder in BROWSER_FINDERS: 67 if(options.browser_type and options.browser_type != 'any' and 68 options.browser_type not in finder.FindAllBrowserTypes(options)): 69 continue 70 curr_browsers = finder.FindAllAvailableBrowsers(options, device) 71 new_default_browser = finder.SelectDefaultBrowser(curr_browsers) 72 if new_default_browser: 73 default_browsers.append(new_default_browser) 74 browsers.extend(curr_browsers) 75 76 if options.browser_type == None: 77 if default_browsers: 78 default_browser = sorted(default_browsers, 79 key=lambda b: b.last_modification_time())[-1] 80 81 logging.warning('--browser omitted. Using most recent local build: %s' % 82 default_browser.browser_type) 83 default_browser.UpdateExecutableIfNeeded() 84 return default_browser 85 86 if len(browsers) == 1: 87 logging.warning('--browser omitted. Using only available browser: %s' % 88 browsers[0].browser_type) 89 browsers[0].UpdateExecutableIfNeeded() 90 return browsers[0] 91 92 raise browser_finder_exceptions.BrowserTypeRequiredException( 93 '--browser must be specified. Available browsers:\n%s' % 94 '\n'.join(sorted(set([b.browser_type for b in browsers])))) 95 96 if options.browser_type == 'any': 97 types = FindAllBrowserTypes(options) 98 def CompareBrowsersOnTypePriority(x, y): 99 x_idx = types.index(x.browser_type) 100 y_idx = types.index(y.browser_type) 101 return x_idx - y_idx 102 browsers.sort(CompareBrowsersOnTypePriority) 103 if len(browsers) >= 1: 104 browsers[0].UpdateExecutableIfNeeded() 105 return browsers[0] 106 else: 107 return None 108 109 matching_browsers = [b for b in browsers 110 if b.browser_type == options.browser_type and b.SupportsOptions(options)] 111 112 chosen_browser = None 113 if len(matching_browsers) == 1: 114 chosen_browser = matching_browsers[0] 115 elif len(matching_browsers) > 1: 116 logging.warning('Multiple browsers of the same type found: %s' % ( 117 repr(matching_browsers))) 118 chosen_browser = sorted(matching_browsers, 119 key=lambda b: b.last_modification_time())[-1] 120 121 if chosen_browser: 122 logging.info('Chose browser: %s' % (repr(chosen_browser))) 123 chosen_browser.UpdateExecutableIfNeeded() 124 125 return chosen_browser 126 127 128@decorators.Cache 129def GetAllAvailableBrowsers(options, device): 130 """Returns a list of available browsers on the device. 131 132 Args: 133 options: A BrowserOptions object. 134 device: The target device, which can be None. 135 136 Returns: 137 A list of browser instances. 138 139 Raises: 140 BrowserFinderException: Options are improperly set, or an error occurred. 141 """ 142 if not device: 143 return [] 144 possible_browsers = [] 145 for browser_finder in BROWSER_FINDERS: 146 possible_browsers.extend( 147 browser_finder.FindAllAvailableBrowsers(options, device)) 148 return possible_browsers 149 150 151@decorators.Cache 152def GetAllAvailableBrowserTypes(options): 153 """Returns a list of available browser types. 154 155 Args: 156 options: A BrowserOptions object. 157 158 Returns: 159 A list of browser type strings. 160 161 Raises: 162 BrowserFinderException: Options are improperly set, or an error occurred. 163 """ 164 devices = device_finder.GetDevicesMatchingOptions(options) 165 possible_browsers = [] 166 for device in devices: 167 possible_browsers.extend(GetAllAvailableBrowsers(options, device)) 168 type_list = set([browser.browser_type for browser in possible_browsers]) 169 # The reference build should be available for mac, linux and win, but the 170 # desktop browser finder won't return it in the list of browsers. 171 for browser in possible_browsers: 172 if (browser.target_os == 'darwin' or browser.target_os.startswith('linux') 173 or browser.target_os.startswith('win')): 174 type_list.add('reference') 175 break 176 type_list = list(type_list) 177 type_list.sort() 178 return type_list 179