| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 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 import urllib2 | |
| 6 import httplib | |
| 7 import socket | |
| 8 import json | |
| 9 import re | |
| 10 import sys | |
| 11 | |
| 12 from telemetry.core import util | |
| 13 from telemetry.core import exceptions | |
| 14 from telemetry.core import user_agent | |
| 15 from telemetry.core import wpr_modes | |
| 16 from telemetry.core import wpr_server | |
| 17 from telemetry.core.chrome import extension_dict_backend | |
| 18 from telemetry.core.chrome import tab_list_backend | |
| 19 from telemetry.core.chrome import tracing_backend | |
| 20 from telemetry.test import options_for_unittests | |
| 21 | |
| 22 class ExtensionsNotSupportedException(Exception): | |
| 23 pass | |
| 24 | |
| 25 class BrowserBackend(object): | |
| 26 """A base class for browser backends. Provides basic functionality | |
| 27 once a remote-debugger port has been established.""" | |
| 28 | |
| 29 WEBPAGEREPLAY_HOST = '127.0.0.1' | |
| 30 | |
| 31 def __init__(self, is_content_shell, supports_extensions, options): | |
| 32 self.browser_type = options.browser_type | |
| 33 self.is_content_shell = is_content_shell | |
| 34 self._supports_extensions = supports_extensions | |
| 35 self.options = options | |
| 36 self._browser = None | |
| 37 self._port = None | |
| 38 | |
| 39 self._inspector_protocol_version = 0 | |
| 40 self._chrome_branch_number = 0 | |
| 41 self._webkit_base_revision = 0 | |
| 42 self._tracing_backend = None | |
| 43 | |
| 44 self.webpagereplay_local_http_port = util.GetAvailableLocalPort() | |
| 45 self.webpagereplay_local_https_port = util.GetAvailableLocalPort() | |
| 46 self.webpagereplay_remote_http_port = self.webpagereplay_local_http_port | |
| 47 self.webpagereplay_remote_https_port = self.webpagereplay_local_https_port | |
| 48 | |
| 49 if options.dont_override_profile and not options_for_unittests.AreSet(): | |
| 50 sys.stderr.write('Warning: Not overriding profile. This can cause ' | |
| 51 'unexpected effects due to profile-specific settings, ' | |
| 52 'such as about:flags settings, cookies, and ' | |
| 53 'extensions.\n') | |
| 54 self._tab_list_backend = tab_list_backend.TabListBackend(self) | |
| 55 self._extension_dict_backend = None | |
| 56 if supports_extensions: | |
| 57 self._extension_dict_backend = \ | |
| 58 extension_dict_backend.ExtensionDictBackend(self) | |
| 59 | |
| 60 def SetBrowser(self, browser): | |
| 61 self._browser = browser | |
| 62 self._tab_list_backend.Init() | |
| 63 | |
| 64 @property | |
| 65 def browser(self): | |
| 66 return self._browser | |
| 67 | |
| 68 @property | |
| 69 def supports_extensions(self): | |
| 70 """True if this browser backend supports extensions.""" | |
| 71 return self._supports_extensions | |
| 72 | |
| 73 @property | |
| 74 def tab_list_backend(self): | |
| 75 return self._tab_list_backend | |
| 76 | |
| 77 @property | |
| 78 def extension_dict_backend(self): | |
| 79 return self._extension_dict_backend | |
| 80 | |
| 81 def GetBrowserStartupArgs(self): | |
| 82 args = [] | |
| 83 args.extend(self.options.extra_browser_args) | |
| 84 args.append('--disable-background-networking') | |
| 85 args.append('--metrics-recording-only') | |
| 86 args.append('--no-first-run') | |
| 87 if self.options.wpr_mode != wpr_modes.WPR_OFF: | |
| 88 args.extend(wpr_server.GetChromeFlags( | |
| 89 self.WEBPAGEREPLAY_HOST, | |
| 90 self.webpagereplay_remote_http_port, | |
| 91 self.webpagereplay_remote_https_port)) | |
| 92 args.extend(user_agent.GetChromeUserAgentArgumentFromType( | |
| 93 self.options.browser_user_agent_type)) | |
| 94 | |
| 95 extensions = [extension.path for extension in | |
| 96 self.options.extensions_to_load if not extension.is_component] | |
| 97 extension_str = ','.join(extensions) | |
| 98 if len(extensions) > 0: | |
| 99 args.append('--load-extension=%s' % extension_str) | |
| 100 | |
| 101 component_extensions = [extension.path for extension in | |
| 102 self.options.extensions_to_load if extension.is_component] | |
| 103 component_extension_str = ','.join(component_extensions) | |
| 104 if len(component_extensions) > 0: | |
| 105 args.append('--load-component-extension=%s' % component_extension_str) | |
| 106 return args | |
| 107 | |
| 108 @property | |
| 109 def wpr_mode(self): | |
| 110 return self.options.wpr_mode | |
| 111 | |
| 112 def _WaitForBrowserToComeUp(self, timeout=None): | |
| 113 def IsBrowserUp(): | |
| 114 try: | |
| 115 self.Request('', timeout=timeout) | |
| 116 except (socket.error, httplib.BadStatusLine, urllib2.URLError): | |
| 117 return False | |
| 118 else: | |
| 119 return True | |
| 120 try: | |
| 121 util.WaitFor(IsBrowserUp, timeout=30) | |
| 122 except util.TimeoutException: | |
| 123 raise exceptions.BrowserGoneException() | |
| 124 | |
| 125 def AllExtensionsLoaded(): | |
| 126 for e in self.options.extensions_to_load: | |
| 127 if not e.extension_id in self._extension_dict_backend: | |
| 128 return False | |
| 129 extension_object = self._extension_dict_backend[e.extension_id] | |
| 130 extension_object.WaitForDocumentReadyStateToBeInteractiveOrBetter() | |
| 131 return True | |
| 132 if self._supports_extensions: | |
| 133 util.WaitFor(AllExtensionsLoaded, timeout=30) | |
| 134 | |
| 135 def _PostBrowserStartupInitialization(self): | |
| 136 # Detect version information. | |
| 137 data = self.Request('version') | |
| 138 resp = json.loads(data) | |
| 139 if 'Protocol-Version' in resp: | |
| 140 self._inspector_protocol_version = resp['Protocol-Version'] | |
| 141 if 'Browser' in resp: | |
| 142 branch_number_match = re.search('Chrome/\d+\.\d+\.(\d+)\.\d+', | |
| 143 resp['Browser']) | |
| 144 else: | |
| 145 branch_number_match = re.search( | |
| 146 'Chrome/\d+\.\d+\.(\d+)\.\d+ (Mobile )?Safari', | |
| 147 resp['User-Agent']) | |
| 148 webkit_version_match = re.search('\((trunk)?\@(\d+)\)', | |
| 149 resp['WebKit-Version']) | |
| 150 | |
| 151 if branch_number_match: | |
| 152 self._chrome_branch_number = int(branch_number_match.group(1)) | |
| 153 else: | |
| 154 # Content Shell returns '' for Browser, for now we have to | |
| 155 # fall-back and assume branch 1025. | |
| 156 self._chrome_branch_number = 1025 | |
| 157 | |
| 158 if webkit_version_match: | |
| 159 self._webkit_base_revision = int(webkit_version_match.group(2)) | |
| 160 return | |
| 161 | |
| 162 # Detection has failed: assume 18.0.1025.168 ~= Chrome Android. | |
| 163 self._inspector_protocol_version = 1.0 | |
| 164 self._chrome_branch_number = 1025 | |
| 165 self._webkit_base_revision = 106313 | |
| 166 | |
| 167 def Request(self, path, timeout=None): | |
| 168 url = 'http://localhost:%i/json' % self._port | |
| 169 if path: | |
| 170 url += '/' + path | |
| 171 req = urllib2.urlopen(url, timeout=timeout) | |
| 172 return req.read() | |
| 173 | |
| 174 @property | |
| 175 def chrome_branch_number(self): | |
| 176 return self._chrome_branch_number | |
| 177 | |
| 178 @property | |
| 179 def supports_tab_control(self): | |
| 180 return self._chrome_branch_number >= 1303 | |
| 181 | |
| 182 @property | |
| 183 def supports_tracing(self): | |
| 184 return self.is_content_shell or self._chrome_branch_number >= 1385 | |
| 185 | |
| 186 def StartTracing(self): | |
| 187 if self._tracing_backend is None: | |
| 188 self._tracing_backend = tracing_backend.TracingBackend(self._port) | |
| 189 self._tracing_backend.BeginTracing() | |
| 190 | |
| 191 def StopTracing(self): | |
| 192 self._tracing_backend.EndTracing() | |
| 193 | |
| 194 def GetTraceResultAndReset(self): | |
| 195 return self._tracing_backend.GetTraceResultAndReset() | |
| 196 | |
| 197 def GetRemotePort(self, _): | |
| 198 return util.GetAvailableLocalPort() | |
| 199 | |
| 200 def Close(self): | |
| 201 if self._tracing_backend: | |
| 202 self._tracing_backend.Close() | |
| 203 self._tracing_backend = None | |
| 204 | |
| 205 def CreateForwarder(self, *port_pairs): | |
| 206 raise NotImplementedError() | |
| 207 | |
| 208 def IsBrowserRunning(self): | |
| 209 raise NotImplementedError() | |
| 210 | |
| 211 def GetStandardOutput(self): | |
| 212 raise NotImplementedError() | |
| OLD | NEW |