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