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.
5 from telemetry.core.backends.chrome import timeline_recorder
6 from telemetry.timeline import inspector_timeline_data
9 class TabBackendException(Exception):
10 """An exception which indicates an error response from devtools inspector."""
14 class InspectorTimeline(timeline_recorder.TimelineRecorder):
15 """Implementation of dev tools timeline."""
17 class Recorder(object):
18 """Utility class to Start and Stop recording timeline.
22 with inspector_timeline.InspectorTimeline.Recorder(tab):
23 # Something to run while the timeline is recording.
25 This is an alternative to directly calling the Start and Stop methods below.
27 def __init__(self, tab):
31 self._tab.StartTimelineRecording()
33 def __exit__(self, *args):
34 self._tab.StopTimelineRecording()
36 def __init__(self, inspector_backend):
37 super(InspectorTimeline, self).__init__()
38 self._inspector_backend = inspector_backend
39 self._is_recording = False
40 self._raw_events = None
43 def is_timeline_recording_running(self):
44 return self._is_recording
47 """Starts recording."""
48 assert not self._is_recording, 'Start should only be called once.'
49 self._raw_events = None
50 self._is_recording = True
51 self._inspector_backend.RegisterDomain(
52 'Timeline', self._OnNotification, self._OnClose)
53 # The 'bufferEvents' parameter below means that events should not be sent
54 # individually as messages, but instead all at once when a Timeline.stop
57 'method': 'Timeline.start',
58 'params': {'bufferEvents': True},
60 self._SendSyncRequest(request)
63 """Stops recording and returns timeline event data."""
64 if not self._is_recording:
66 request = {'method': 'Timeline.stop'}
67 result = self._SendSyncRequest(request)
68 self._inspector_backend.UnregisterDomain('Timeline')
69 self._is_recording = False
71 # TODO: Backward compatibility. Needs to be removed when
73 if 'events' in result:
74 raw_events = result['events']
75 else: # In M38 events will arrive via Timeline.stopped event.
76 raw_events = self._raw_events
77 self._raw_events = None
78 return inspector_timeline_data.InspectorTimelineData(raw_events)
80 def _SendSyncRequest(self, request, timeout=60):
81 """Sends a devtools remote debugging protocol request.
83 The types of request that are valid is determined by protocol.json:
84 https://src.chromium.org/viewvc/blink/trunk/Source/devtools/protocol.json
87 request: Request dict, may contain the keys 'method' and 'params'.
88 timeout: Number of seconds to wait for a response.
91 The result given in the response message.
94 TabBackendException: The response indicates an error occurred.
96 response = self._inspector_backend.SyncRequest(request, timeout)
97 if 'error' in response:
98 raise TabBackendException(response['error']['message'])
99 return response['result']
101 def _OnNotification(self, msg):
102 """Handler called when a message is received."""
103 # Since 'Timeline.start' was invoked with the 'bufferEvents' parameter,
104 # the events will arrive in Timeline.stopped event.
105 if msg['method'] == 'Timeline.stopped' and 'events' in msg['params']:
106 self._raw_events = msg['params']['events']
109 """Handler called when a domain is unregistered."""