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 111 b.SupportsOptions(options.browser_options)] 112 113 chosen_browser = None 114 if len(matching_browsers) == 1: 115 chosen_browser = matching_browsers[0] 116 elif len(matching_browsers) > 1: 117 logging.warning('Multiple browsers of the same type found: %s' % ( 118 repr(matching_browsers))) 119 chosen_browser = sorted(matching_browsers, 120 key=lambda b: b.last_modification_time())[-1] 121 122 if chosen_browser: 123 logging.info('Chose browser: %s' % (repr(chosen_browser))) 124 chosen_browser.UpdateExecutableIfNeeded() 125 126 return chosen_browser 127 128 129@decorators.Cache 130def GetAllAvailableBrowsers(options, device): 131 """Returns a list of available browsers on the device. 132 133 Args: 134 options: A BrowserOptions object. 135 device: The target device, which can be None. 136 137 Returns: 138 A list of browser instances. 139 140 Raises: 141 BrowserFinderException: Options are improperly set, or an error occurred. 142 """ 143 if not device: 144 return [] 145 possible_browsers = [] 146 for browser_finder in BROWSER_FINDERS: 147 possible_browsers.extend( 148 browser_finder.FindAllAvailableBrowsers(options, device)) 149 return possible_browsers 150 151 152@decorators.Cache 153def GetAllAvailableBrowserTypes(options): 154 """Returns a list of available browser types. 155 156 Args: 157 options: A BrowserOptions object. 158 159 Returns: 160 A list of browser type strings. 161 162 Raises: 163 BrowserFinderException: Options are improperly set, or an error occurred. 164 """ 165 devices = device_finder.GetDevicesMatchingOptions(options) 166 possible_browsers = [] 167 for device in devices: 168 possible_browsers.extend(GetAllAvailableBrowsers(options, device)) 169 type_list = set([browser.browser_type for browser in possible_browsers]) 170 # The reference build should be available for mac, linux and win, but the 171 # desktop browser finder won't return it in the list of browsers. 172 for browser in possible_browsers: 173 if (browser.target_os == 'darwin' or browser.target_os.startswith('linux') 174 or browser.target_os.startswith('win')): 175 type_list.add('reference') 176 break 177 type_list = list(type_list) 178 type_list.sort() 179 return type_list 180