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 5import json 6 7from telemetry.core import exceptions 8from telemetry.core import util 9from telemetry.internal.backends.chrome_inspector import inspector_backend_list 10from telemetry.internal.browser import tab 11 12 13class TabUnexpectedResponseException(exceptions.DevtoolsTargetCrashException): 14 pass 15 16 17class TabListBackend(inspector_backend_list.InspectorBackendList): 18 """A dynamic sequence of tab.Tabs in UI order.""" 19 20 def __init__(self, browser_backend): 21 super(TabListBackend, self).__init__(browser_backend) 22 23 def New(self, timeout): 24 """Makes a new tab. 25 26 Returns: 27 A Tab object. 28 29 Raises: 30 devtools_http.DevToolsClientConnectionError 31 """ 32 if not self._browser_backend.supports_tab_control: 33 raise NotImplementedError("Browser doesn't support tab control.") 34 response = self._browser_backend.devtools_client.RequestNewTab(timeout) 35 try: 36 response = json.loads(response) 37 context_id = response['id'] 38 except (KeyError, ValueError): 39 raise TabUnexpectedResponseException( 40 app=self._browser_backend.browser, 41 msg='Received response: %s' % response) 42 return self.GetBackendFromContextId(context_id) 43 44 def CloseTab(self, tab_id, timeout=300): 45 """Closes the tab with the given debugger_url. 46 47 Raises: 48 devtools_http.DevToolsClientConnectionError 49 devtools_client_backend.TabNotFoundError 50 TabUnexpectedResponseException 51 exceptions.TimeoutException 52 """ 53 assert self._browser_backend.supports_tab_control 54 # TODO(dtu): crbug.com/160946, allow closing the last tab on some platforms. 55 # For now, just create a new tab before closing the last tab. 56 if len(self) <= 1: 57 self.New(timeout) 58 59 response = self._browser_backend.devtools_client.CloseTab(tab_id, timeout) 60 61 if response != 'Target is closing': 62 raise TabUnexpectedResponseException( 63 app=self._browser_backend.browser, 64 msg='Received response: %s' % response) 65 66 util.WaitFor(lambda: tab_id not in self.IterContextIds(), timeout=5) 67 68 def ActivateTab(self, tab_id, timeout=30): 69 """Activates the tab with the given debugger_url. 70 71 Raises: 72 devtools_http.DevToolsClientConnectionError 73 devtools_client_backend.TabNotFoundError 74 TabUnexpectedResponseException 75 """ 76 assert self._browser_backend.supports_tab_control 77 78 response = self._browser_backend.devtools_client.ActivateTab(tab_id, 79 timeout) 80 81 if response != 'Target activated': 82 raise TabUnexpectedResponseException( 83 app=self._browser_backend.browser, 84 msg='Received response: %s' % response) 85 86 def Get(self, index, ret): 87 """Returns self[index] if it exists, or ret if index is out of bounds.""" 88 if len(self) <= index: 89 return ret 90 return self[index] 91 92 def ShouldIncludeContext(self, context): 93 if 'type' in context: 94 return (context['type'] == 'page' or 95 context['url'] == 'chrome://media-router/') 96 # TODO: For compatibility with Chrome before r177683. 97 # This check is not completely correct, see crbug.com/190592. 98 return not context['url'].startswith('chrome-extension://') 99 100 def CreateWrapper(self, inspector_backend): 101 return tab.Tab(inspector_backend, self, self._browser_backend.browser) 102 103 def _HandleDevToolsConnectionError(self, error): 104 if not self._browser_backend.IsAppRunning(): 105 error.AddDebuggingMessage('The browser is not running. It probably ' 106 'crashed.') 107 elif not self._browser_backend.HasBrowserFinishedLaunching(): 108 error.AddDebuggingMessage('The browser exists but cannot be reached.') 109 else: 110 error.AddDebuggingMessage('The browser exists and can be reached. ' 111 'The devtools target probably crashed.') 112