1# Copyright 2015 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
6import logging
7import socket
8import traceback
9
10from telemetry.internal.backends.chrome_inspector import inspector_websocket
11from telemetry.internal.backends.chrome_inspector import websocket
12
13
14class MemoryTimeoutException(Exception):
15  pass
16
17
18class MemoryUnrecoverableException(Exception):
19  pass
20
21
22class MemoryUnexpectedResponseException(Exception):
23  pass
24
25
26class MemoryBackend(object):
27
28  def __init__(self, inspector_socket):
29    self._inspector_websocket = inspector_socket
30
31  def SetMemoryPressureNotificationsSuppressed(self, suppressed, timeout=30):
32    """Enable/disable suppressing memory pressure notifications.
33
34    Args:
35      suppressed: If true, memory pressure notifications will be suppressed.
36      timeout: The timeout in seconds.
37
38    Raises:
39      MemoryTimeoutException: If more than |timeout| seconds has passed
40      since the last time any data is received.
41      MemoryUnrecoverableException: If there is a websocket error.
42      MemoryUnexpectedResponseException: If the response contains an error
43      or does not contain the expected result.
44    """
45    self._SendMemoryRequest('setPressureNotificationsSuppressed',
46                            {'suppressed': suppressed}, timeout)
47
48  def SimulateMemoryPressureNotification(self, pressure_level, timeout=30):
49    """Simulate a memory pressure notification.
50
51    Args:
52      pressure level: The memory pressure level of the notification ('moderate'
53          or 'critical').
54      timeout: The timeout in seconds.
55
56    Raises:
57      MemoryTimeoutException: If more than |timeout| seconds has passed
58      since the last time any data is received.
59      MemoryUnrecoverableException: If there is a websocket error.
60      MemoryUnexpectedResponseException: If the response contains an error
61      or does not contain the expected result.
62    """
63    self._SendMemoryRequest('simulatePressureNotification',
64                            {'level': pressure_level}, timeout)
65
66  def _SendMemoryRequest(self, command, params, timeout):
67    method = 'Memory.%s' % command
68    request = {
69      'method': method,
70      'params': params
71    }
72    try:
73      response = self._inspector_websocket.SyncRequest(request, timeout)
74    except websocket.WebSocketTimeoutException:
75      raise MemoryTimeoutException(
76          'Exception raised while sending a %s request:\n%s' %
77              (method, traceback.format_exc()))
78    except (socket.error, websocket.WebSocketException,
79            inspector_websocket.WebSocketDisconnected):
80      raise MemoryUnrecoverableException(
81          'Exception raised while sending a %s request:\n%s' %
82              (method, traceback.format_exc()))
83
84    if 'error' in response:
85      code = response['error']['code']
86      if code == inspector_websocket.InspectorWebsocket.METHOD_NOT_FOUND_CODE:
87        logging.warning(
88            '%s DevTools method not supported by the browser' % method)
89      else:
90        raise MemoryUnexpectedResponseException(
91            'Inspector returned unexpected response for %s:\n%s' %
92                (method, json.dumps(response, indent=2)))
93
94  def Close(self):
95    self._inspector_websocket = None
96