Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: tools/telemetry/telemetry/inspector_backend.py

Issue 12278015: [Telemetry] Reorganize everything. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Re-add shebangs. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 import json
5 import logging
6 import socket
7 import sys
8
9 from telemetry import inspector_console
10 from telemetry import inspector_page
11 from telemetry import inspector_runtime
12 from telemetry import inspector_timeline
13 from telemetry import png_bitmap
14 from telemetry import tab_crash_exception
15 from telemetry import util
16 from telemetry import websocket
17
18 class InspectorException(Exception):
19 pass
20
21 class InspectorBackend(object):
22 def __init__(self, browser, browser_backend, debugger_url):
23 assert debugger_url
24 self._browser = browser
25 self._browser_backend = browser_backend
26 self._debugger_url = debugger_url
27 self._socket = None
28 self._domain_handlers = {}
29 self._cur_socket_timeout = 0
30 self._next_request_id = 0
31
32 self._console = inspector_console.InspectorConsole(self)
33 self._page = inspector_page.InspectorPage(self)
34 self._runtime = inspector_runtime.InspectorRuntime(self)
35 self._timeline = inspector_timeline.InspectorTimeline(self)
36
37 def __del__(self):
38 self.Disconnect()
39
40 def _Connect(self):
41 if self._socket:
42 return
43 self._socket = websocket.create_connection(self._debugger_url)
44 self._cur_socket_timeout = 0
45 self._next_request_id = 0
46
47 def Disconnect(self):
48 for _, handlers in self._domain_handlers.items():
49 _, will_close_handler = handlers
50 will_close_handler()
51 self._domain_handlers = {}
52
53 if self._socket:
54 self._socket.close()
55 self._socket = None
56
57 # General public methods.
58
59 @property
60 def browser(self):
61 return self._browser
62
63 @property
64 def url(self):
65 self.Disconnect()
66 return self._browser_backend.tab_list_backend.GetTabUrl(self._debugger_url)
67
68 def Activate(self):
69 self._Connect()
70 self._browser_backend.tab_list_backend.ActivateTab(self._debugger_url)
71
72 def Close(self):
73 self.Disconnect()
74 self._browser_backend.tab_list_backend.CloseTab(self._debugger_url)
75
76 # Public methods implemented in JavaScript.
77
78 def WaitForDocumentReadyStateToBeComplete(self, timeout):
79 util.WaitFor(
80 lambda: self._runtime.Evaluate('document.readyState') == 'complete',
81 timeout)
82
83 def WaitForDocumentReadyStateToBeInteractiveOrBetter(
84 self, timeout):
85 def IsReadyStateInteractiveOrBetter():
86 rs = self._runtime.Evaluate('document.readyState')
87 return rs == 'complete' or rs == 'interactive'
88 util.WaitFor(IsReadyStateInteractiveOrBetter, timeout)
89
90 @property
91 def screenshot_supported(self):
92 if self._runtime.Evaluate(
93 'window.chrome.gpuBenchmarking === undefined'):
94 return False
95
96 if self._runtime.Evaluate(
97 'window.chrome.gpuBenchmarking.beginWindowSnapshotPNG === undefined'):
98 return False
99
100 # TODO(dtu): Also check for Chrome branch number, because of a bug in
101 # beginWindowSnapshotPNG in older versions. crbug.com/171592
102
103 return True
104
105 def Screenshot(self, timeout):
106 if self._runtime.Evaluate(
107 'window.chrome.gpuBenchmarking === undefined'):
108 raise Exception("Browser was not started with --enable-gpu-benchmarking")
109
110 if self._runtime.Evaluate(
111 'window.chrome.gpuBenchmarking.beginWindowSnapshotPNG === undefined'):
112 raise Exception("Browser does not support window snapshot API.")
113
114 self._runtime.Evaluate("""
115 if(!window.__telemetry) {
116 window.__telemetry = {}
117 }
118 window.__telemetry.snapshotComplete = false;
119 window.__telemetry.snapshotData = null;
120 window.chrome.gpuBenchmarking.beginWindowSnapshotPNG(
121 function(snapshot) {
122 window.__telemetry.snapshotData = snapshot;
123 window.__telemetry.snapshotComplete = true;
124 }
125 );
126 """)
127
128 def IsSnapshotComplete():
129 return self._runtime.Evaluate('window.__telemetry.snapshotComplete')
130
131 util.WaitFor(IsSnapshotComplete, timeout)
132
133 snap = self._runtime.Evaluate("""
134 (function() {
135 var data = window.__telemetry.snapshotData;
136 delete window.__telemetry.snapshotComplete;
137 delete window.__telemetry.snapshotData;
138 return data;
139 })()
140 """)
141 if snap:
142 return png_bitmap.PngBitmap(snap['data'])
143 return None
144
145 # Console public methods.
146
147 @property
148 def message_output_stream(self): # pylint: disable=E0202
149 return self._console.message_output_stream
150
151 @message_output_stream.setter
152 def message_output_stream(self, stream): # pylint: disable=E0202
153 self._console.message_output_stream = stream
154
155 # Page public methods.
156
157 def PerformActionAndWaitForNavigate(self, action_function, timeout):
158 self._page.PerformActionAndWaitForNavigate(action_function, timeout)
159
160 def Navigate(self, url, timeout):
161 self._page.Navigate(url, timeout)
162
163 def GetCookieByName(self, name, timeout):
164 return self._page.GetCookieByName(name, timeout)
165
166 # Runtime public methods.
167
168 def ExecuteJavaScript(self, expr, timeout):
169 self._runtime.Execute(expr, timeout)
170
171 def EvaluateJavaScript(self, expr, timeout):
172 return self._runtime.Evaluate(expr, timeout)
173
174 # Timeline public methods.
175
176 @property
177 def timeline_model(self):
178 return self._timeline.timeline_model
179
180 def StartTimelineRecording(self):
181 self._timeline.Start()
182
183 def StopTimelineRecording(self):
184 self._timeline.Stop()
185
186 # Methods used internally by other backends.
187
188 def DispatchNotifications(self, timeout=10):
189 self._Connect()
190 self._SetTimeout(timeout)
191
192 try:
193 data = self._socket.recv()
194 except (socket.error, websocket.WebSocketException):
195 if self._browser_backend.tab_list_backend.DoesDebuggerUrlExist(
196 self._debugger_url):
197 return
198 raise tab_crash_exception.TabCrashException()
199
200 res = json.loads(data)
201 logging.debug('got [%s]', data)
202 if 'method' in res:
203 self._HandleNotification(res)
204
205 def _HandleNotification(self, res):
206 if (res['method'] == 'Inspector.detached' and
207 res.get('params', {}).get('reason','') == 'replaced_with_devtools'):
208 self._WaitForInspectorToGoAwayAndReconnect()
209 return
210
211 mname = res['method']
212 dot_pos = mname.find('.')
213 domain_name = mname[:dot_pos]
214 if domain_name in self._domain_handlers:
215 try:
216 self._domain_handlers[domain_name][0](res)
217 except Exception:
218 import traceback
219 traceback.print_exc()
220 else:
221 logging.debug('Unhandled inspector message: %s', res)
222
223 def SendAndIgnoreResponse(self, req):
224 self._Connect()
225 req['id'] = self._next_request_id
226 self._next_request_id += 1
227 data = json.dumps(req)
228 self._socket.send(data)
229 logging.debug('sent [%s]', data)
230
231 def _SetTimeout(self, timeout):
232 if self._cur_socket_timeout != timeout:
233 self._socket.settimeout(timeout)
234 self._cur_socket_timeout = timeout
235
236 def _WaitForInspectorToGoAwayAndReconnect(self):
237 sys.stderr.write('The connection to Chrome was lost to the Inspector UI.\n')
238 sys.stderr.write('Telemetry is waiting for the inspector to be closed...\n')
239 self._socket.close()
240 self._socket = None
241 def IsBack():
242 return self._browser_backend.tab_list_backend.DoesDebuggerUrlExist(
243 self._debugger_url)
244 util.WaitFor(IsBack, 512, 0.5)
245 sys.stderr.write('\n')
246 sys.stderr.write('Inspector\'s UI closed. Telemetry will now resume.\n')
247 self._Connect()
248
249 def SyncRequest(self, req, timeout=10):
250 self._Connect()
251 # TODO(nduca): Listen to the timeout argument
252 # pylint: disable=W0613
253 self._SetTimeout(timeout)
254 self.SendAndIgnoreResponse(req)
255
256 while True:
257 try:
258 data = self._socket.recv()
259 except (socket.error, websocket.WebSocketException):
260 if self._browser_backend.tab_list_backend.DoesDebuggerUrlExist(
261 self._debugger_url):
262 raise util.TimeoutException(
263 'Timed out waiting for reply. This is unusual.')
264 raise tab_crash_exception.TabCrashException()
265
266 res = json.loads(data)
267 logging.debug('got [%s]', data)
268 if 'method' in res:
269 self._HandleNotification(res)
270 continue
271
272 if res['id'] != req['id']:
273 logging.debug('Dropped reply: %s', json.dumps(res))
274 continue
275 return res
276
277 def RegisterDomain(self,
278 domain_name, notification_handler, will_close_handler):
279 """Registers a given domain for handling notification methods.
280
281 For example, given inspector_backend:
282 def OnConsoleNotification(msg):
283 if msg['method'] == 'Console.messageAdded':
284 print msg['params']['message']
285 return
286 def OnConsoleClose(self):
287 pass
288 inspector_backend.RegisterDomain('Console',
289 OnConsoleNotification, OnConsoleClose)
290 """
291 assert domain_name not in self._domain_handlers
292 self._domain_handlers[domain_name] = (notification_handler,
293 will_close_handler)
294
295 def UnregisterDomain(self, domain_name):
296 """Unregisters a previously registered domain."""
297 assert domain_name in self._domain_handlers
298 self._domain_handlers.pop(domain_name)
OLDNEW
« no previous file with comments | « tools/telemetry/telemetry/gtest_testrunner.py ('k') | tools/telemetry/telemetry/inspector_console.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698