| OLD | NEW |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import os | 5 import os |
| 6 import shutil | 6 import shutil |
| 7 import stat | 7 import stat |
| 8 import sys | 8 import sys |
| 9 import tempfile | 9 import tempfile |
| 10 import traceback | 10 import traceback |
| 11 | 11 |
| 12 from telemetry.internal.platform import tracing_agent | 12 from telemetry.internal.platform import tracing_agent |
| 13 from telemetry.internal.platform.tracing_agent import ( | 13 from telemetry.internal.platform.tracing_agent import ( |
| 14 chrome_tracing_devtools_manager) | 14 chrome_tracing_devtools_manager) |
| 15 from telemetry.timeline import tracing_config |
| 15 | 16 |
| 16 _DESKTOP_OS_NAMES = ['linux', 'mac', 'win'] | 17 _DESKTOP_OS_NAMES = ['linux', 'mac', 'win'] |
| 18 _STARTUP_TRACING_OS_NAMES = _DESKTOP_OS_NAMES + ['android'] |
| 17 | 19 |
| 18 # The trace config file path should be the same as specified in | 20 # The trace config file path should be the same as specified in |
| 19 # src/components/tracing/startup_tracing.cc | 21 # src/components/tracing/startup_tracing.cc |
| 20 _CHROME_TRACE_CONFIG_DIR_ANDROID = '/data/local/' | 22 _CHROME_TRACE_CONFIG_DIR_ANDROID = '/data/local/' |
| 21 _CHROME_TRACE_CONFIG_FILE_NAME = 'chrome-trace-config.json' | 23 _CHROME_TRACE_CONFIG_FILE_NAME = 'chrome-trace-config.json' |
| 22 | 24 |
| 23 | 25 |
| 24 class ChromeTracingStartedError(Exception): | 26 class ChromeTracingStartedError(Exception): |
| 25 pass | 27 pass |
| 26 | 28 |
| 27 | 29 |
| 28 class ChromeTracingStoppedError(Exception): | 30 class ChromeTracingStoppedError(Exception): |
| 29 pass | 31 pass |
| 30 | 32 |
| 31 | 33 |
| 32 class ChromeTracingAgent(tracing_agent.TracingAgent): | 34 class ChromeTracingAgent(tracing_agent.TracingAgent): |
| 33 def __init__(self, platform_backend): | 35 def __init__(self, platform_backend): |
| 34 super(ChromeTracingAgent, self).__init__(platform_backend) | 36 super(ChromeTracingAgent, self).__init__(platform_backend) |
| 37 self._trace_config = None |
| 35 self._trace_config_file = None | 38 self._trace_config_file = None |
| 36 | 39 |
| 37 @property | 40 @property |
| 41 def trace_config(self): |
| 42 # Trace config is also used to check if Chrome tracing is running or not. |
| 43 return self._trace_config |
| 44 |
| 45 @property |
| 38 def trace_config_file(self): | 46 def trace_config_file(self): |
| 39 return self._trace_config_file | 47 return self._trace_config_file |
| 40 | 48 |
| 41 @classmethod | 49 @classmethod |
| 50 def IsStartupTracingSupported(cls, platform_backend): |
| 51 if platform_backend.GetOSName() in _STARTUP_TRACING_OS_NAMES: |
| 52 return True |
| 53 else: |
| 54 return False |
| 55 |
| 56 @classmethod |
| 42 def IsSupported(cls, platform_backend): | 57 def IsSupported(cls, platform_backend): |
| 43 return chrome_tracing_devtools_manager.IsSupported(platform_backend) | 58 if cls.IsStartupTracingSupported(platform_backend): |
| 59 return True |
| 60 else: |
| 61 return chrome_tracing_devtools_manager.IsSupported(platform_backend) |
| 44 | 62 |
| 45 def Start(self, trace_options, category_filter, timeout): | 63 def _StartStartupTracing(self, config): |
| 46 if not trace_options.enable_chrome_trace: | 64 if not self.IsStartupTracingSupported(self._platform_backend): |
| 65 return False |
| 66 self._CreateTraceConfigFile(config) |
| 67 return True |
| 68 |
| 69 def _StartDevToolsTracing(self, trace_options, category_filter, timeout): |
| 70 if not chrome_tracing_devtools_manager.IsSupported(self._platform_backend): |
| 47 return False | 71 return False |
| 48 devtools_clients = (chrome_tracing_devtools_manager | 72 devtools_clients = (chrome_tracing_devtools_manager |
| 49 .GetActiveDevToolsClients(self._platform_backend)) | 73 .GetActiveDevToolsClients(self._platform_backend)) |
| 50 if not devtools_clients: | 74 if not devtools_clients: |
| 51 return False | 75 return False |
| 52 for client in devtools_clients: | 76 for client in devtools_clients: |
| 53 if client.is_tracing_running: | 77 if client.is_tracing_running: |
| 54 raise ChromeTracingStartedError( | 78 raise ChromeTracingStartedError( |
| 55 'Tracing is already running on devtools at port %s on platform' | 79 'Tracing is already running on devtools at port %s on platform' |
| 56 'backend %s.' % (client.remote_port, self._platform_backend)) | 80 'backend %s.' % (client.remote_port, self._platform_backend)) |
| 57 client.StartChromeTracing( | 81 client.StartChromeTracing( |
| 58 trace_options, category_filter.filter_string, timeout) | 82 trace_options, category_filter.filter_string, timeout) |
| 59 return True | 83 return True |
| 60 | 84 |
| 85 def Start(self, trace_options, category_filter, timeout): |
| 86 if not trace_options.enable_chrome_trace: |
| 87 return False |
| 88 |
| 89 if self._trace_config: |
| 90 raise ChromeTracingStartedError( |
| 91 'Tracing is already running on platform backend %s.' |
| 92 % self._platform_backend) |
| 93 |
| 94 # Chrome tracing Agent needs to start tracing for chrome browsers that are |
| 95 # not yet started, and for the ones that already are. For the former, we |
| 96 # first setup the trace_config_file, which allows browsers that starts after |
| 97 # this point to use it for enabling tracing upon browser startup. For the |
| 98 # latter, we invoke start tracing command through devtools for browsers that |
| 99 # are already started and tracked by chrome_tracing_devtools_manager. |
| 100 config = tracing_config.TracingConfig(trace_options, category_filter) |
| 101 started_startup_tracing = self._StartStartupTracing(config) |
| 102 started_devtools_tracing = self._StartDevToolsTracing( |
| 103 trace_options, category_filter, timeout) |
| 104 if started_startup_tracing or started_devtools_tracing: |
| 105 self._trace_config = config |
| 106 return True |
| 107 return False |
| 108 |
| 61 def Stop(self, trace_data_builder): | 109 def Stop(self, trace_data_builder): |
| 110 if not self._trace_config: |
| 111 raise ChromeTracingStoppedError( |
| 112 'Tracing is not running on platform backend %s.' |
| 113 % self._platform_backend) |
| 114 |
| 115 if self.IsStartupTracingSupported(self._platform_backend): |
| 116 self._RemoveTraceConfigFile() |
| 117 |
| 62 # We get all DevTools clients including the stale ones, so that we get an | 118 # We get all DevTools clients including the stale ones, so that we get an |
| 63 # exception if there is a stale client. This is because we will potentially | 119 # exception if there is a stale client. This is because we will potentially |
| 64 # lose data if there is a stale client. | 120 # lose data if there is a stale client. |
| 65 devtools_clients = (chrome_tracing_devtools_manager | 121 devtools_clients = (chrome_tracing_devtools_manager |
| 66 .GetDevToolsClients(self._platform_backend)) | 122 .GetDevToolsClients(self._platform_backend)) |
| 67 raised_execption_messages = [] | 123 raised_execption_messages = [] |
| 68 for client in devtools_clients: | 124 for client in devtools_clients: |
| 69 try: | 125 try: |
| 70 client.StopChromeTracing(trace_data_builder) | 126 client.StopChromeTracing(trace_data_builder) |
| 71 except Exception: | 127 except Exception: |
| 72 raised_execption_messages.append( | 128 raised_execption_messages.append( |
| 73 'Error when trying to stop Chrome tracing on devtools at port %s:\n%s' | 129 'Error when trying to stop Chrome tracing on devtools at port %s:\n%s' |
| 74 % (client.remote_port, | 130 % (client.remote_port, |
| 75 ''.join(traceback.format_exception(*sys.exc_info())))) | 131 ''.join(traceback.format_exception(*sys.exc_info())))) |
| 76 | 132 |
| 133 self._trace_config = None |
| 77 if raised_execption_messages: | 134 if raised_execption_messages: |
| 78 raise ChromeTracingStoppedError( | 135 raise ChromeTracingStoppedError( |
| 79 'Exceptions raised when trying to stop Chrome devtool tracing:\n' + | 136 'Exceptions raised when trying to stop Chrome devtool tracing:\n' + |
| 80 '\n'.join(raised_execption_messages)) | 137 '\n'.join(raised_execption_messages)) |
| 81 | 138 |
| 139 def _CreateTraceConfigFileString(self, config): |
| 140 # See src/components/tracing/trace_config_file.h for the format |
| 141 trace_config_str = config.GetTraceConfigJsonString() |
| 142 return '{"trace_config":' + trace_config_str + '}' |
| 143 |
| 82 def _CreateTraceConfigFile(self, config): | 144 def _CreateTraceConfigFile(self, config): |
| 83 assert not self._trace_config_file | 145 assert not self._trace_config_file |
| 84 if self._platform_backend.GetOSName() == 'android': | 146 if self._platform_backend.GetOSName() == 'android': |
| 85 self._trace_config_file = os.path.join(_CHROME_TRACE_CONFIG_DIR_ANDROID, | 147 self._trace_config_file = os.path.join(_CHROME_TRACE_CONFIG_DIR_ANDROID, |
| 86 _CHROME_TRACE_CONFIG_FILE_NAME) | 148 _CHROME_TRACE_CONFIG_FILE_NAME) |
| 87 self._platform_backend.device.WriteFile(self._trace_config_file, | 149 self._platform_backend.device.WriteFile(self._trace_config_file, |
| 88 config.GetTraceConfigJsonString(), as_root=True) | 150 self._CreateTraceConfigFileString(config), as_root=True) |
| 89 elif self._platform_backend.GetOSName() in _DESKTOP_OS_NAMES: | 151 elif self._platform_backend.GetOSName() in _DESKTOP_OS_NAMES: |
| 90 self._trace_config_file = os.path.join(tempfile.mkdtemp(), | 152 self._trace_config_file = os.path.join(tempfile.mkdtemp(), |
| 91 _CHROME_TRACE_CONFIG_FILE_NAME) | 153 _CHROME_TRACE_CONFIG_FILE_NAME) |
| 92 with open(self._trace_config_file, 'w') as f: | 154 with open(self._trace_config_file, 'w') as f: |
| 93 f.write(config.GetTraceConfigJsonString()) | 155 f.write(self._CreateTraceConfigFileString(config)) |
| 94 os.chmod(self._trace_config_file, | 156 os.chmod(self._trace_config_file, |
| 95 os.stat(self._trace_config_file).st_mode | stat.S_IROTH) | 157 os.stat(self._trace_config_file).st_mode | stat.S_IROTH) |
| 96 else: | 158 else: |
| 97 raise NotImplementedError | 159 raise NotImplementedError |
| 98 | 160 |
| 99 def _RemoveTraceConfigFile(self): | 161 def _RemoveTraceConfigFile(self): |
| 100 if not self._trace_config_file: | 162 if not self._trace_config_file: |
| 101 return | 163 return |
| 102 if self._platform_backend.GetOSName() == 'android': | 164 if self._platform_backend.GetOSName() == 'android': |
| 103 self._platform_backend.device.RunShellCommand( | 165 self._platform_backend.device.RunShellCommand( |
| 104 ['rm', '-f', self._trace_config_file], check_return=True, | 166 ['rm', '-f', self._trace_config_file], check_return=True, |
| 105 as_root=True) | 167 as_root=True) |
| 106 elif self._platform_backend.GetOSName() in _DESKTOP_OS_NAMES: | 168 elif self._platform_backend.GetOSName() in _DESKTOP_OS_NAMES: |
| 107 if os.path.exists(self._trace_config_file): | 169 if os.path.exists(self._trace_config_file): |
| 108 os.remove(self._trace_config_file) | 170 os.remove(self._trace_config_file) |
| 109 shutil.rmtree(os.path.dirname(self._trace_config_file)) | 171 shutil.rmtree(os.path.dirname(self._trace_config_file)) |
| 110 else: | 172 else: |
| 111 raise NotImplementedError | 173 raise NotImplementedError |
| 112 self._trace_config_file = None | 174 self._trace_config_file = None |
| OLD | NEW |