Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / devtools / devtools_tracing_handler.cc
blobde81bf3cb6ad3b3f556c7cb779e8cb464007d2d4
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.
5 #include "content/browser/devtools/devtools_tracing_handler.h"
7 #include <cmath>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/debug/trace_event_impl.h"
12 #include "base/file_util.h"
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/location.h"
16 #include "base/memory/ref_counted_memory.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/time/time.h"
20 #include "base/timer/timer.h"
21 #include "base/values.h"
22 #include "content/browser/devtools/devtools_http_handler_impl.h"
23 #include "content/browser/devtools/devtools_protocol_constants.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/tracing_controller.h"
27 namespace content {
29 namespace {
31 const char kRecordUntilFull[] = "record-until-full";
32 const char kRecordContinuously[] = "record-continuously";
33 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
34 const char kEnableSampling[] = "enable-sampling";
36 void ReadFile(
37 const base::FilePath& path,
38 const base::Callback<void(const scoped_refptr<base::RefCountedString>&)>
39 callback) {
40 std::string trace_data;
41 if (!base::ReadFileToString(path, &trace_data))
42 LOG(ERROR) << "Failed to read file: " << path.value();
43 base::DeleteFile(path, false);
44 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
45 base::Bind(callback, make_scoped_refptr(
46 base::RefCountedString::TakeString(&trace_data))));
49 } // namespace
51 const char* DevToolsTracingHandler::kDefaultCategories =
52 "-*,disabled-by-default-devtools.timeline*";
53 const double DevToolsTracingHandler::kDefaultReportingInterval = 1000.0;
54 const double DevToolsTracingHandler::kMinimumReportingInterval = 250.0;
56 DevToolsTracingHandler::DevToolsTracingHandler(
57 DevToolsTracingHandler::Target target)
58 : weak_factory_(this), target_(target), is_recording_(false) {
59 RegisterCommandHandler(devtools::Tracing::start::kName,
60 base::Bind(&DevToolsTracingHandler::OnStart,
61 base::Unretained(this)));
62 RegisterCommandHandler(devtools::Tracing::end::kName,
63 base::Bind(&DevToolsTracingHandler::OnEnd,
64 base::Unretained(this)));
65 RegisterCommandHandler(devtools::Tracing::getCategories::kName,
66 base::Bind(&DevToolsTracingHandler::OnGetCategories,
67 base::Unretained(this)));
68 RegisterNotificationHandler(devtools::Tracing::started::kName,
69 base::Bind(&DevToolsTracingHandler::OnTracingStarted,
70 base::Unretained(this)));
71 RegisterNotificationHandler(devtools::Tracing::stopped::kName,
72 base::Bind(&DevToolsTracingHandler::OnTracingStopped,
73 base::Unretained(this)));
76 DevToolsTracingHandler::~DevToolsTracingHandler() {
79 void DevToolsTracingHandler::BeginReadingRecordingResult(
80 const base::FilePath& path) {
81 BrowserThread::PostTask(
82 BrowserThread::FILE, FROM_HERE,
83 base::Bind(&ReadFile, path,
84 base::Bind(&DevToolsTracingHandler::ReadRecordingResult,
85 weak_factory_.GetWeakPtr())));
88 void DevToolsTracingHandler::ReadRecordingResult(
89 const scoped_refptr<base::RefCountedString>& trace_data) {
90 if (trace_data->data().size()) {
91 scoped_ptr<base::Value> trace_value(base::JSONReader::Read(
92 trace_data->data()));
93 base::DictionaryValue* dictionary = NULL;
94 bool ok = trace_value->GetAsDictionary(&dictionary);
95 DCHECK(ok);
96 base::ListValue* list = NULL;
97 ok = dictionary->GetList("traceEvents", &list);
98 DCHECK(ok);
99 std::string buffer;
100 for (size_t i = 0; i < list->GetSize(); ++i) {
101 std::string item;
102 base::Value* item_value;
103 list->Get(i, &item_value);
104 base::JSONWriter::Write(item_value, &item);
105 if (buffer.size())
106 buffer.append(",");
107 buffer.append(item);
108 const size_t kMessageSizeThreshold = 1024 * 1024;
109 if (buffer.size() > kMessageSizeThreshold) {
110 OnTraceDataCollected(buffer);
111 buffer.clear();
114 if (buffer.size())
115 OnTraceDataCollected(buffer);
118 SendNotification(devtools::Tracing::tracingComplete::kName, NULL);
121 void DevToolsTracingHandler::OnTraceDataCollected(
122 const std::string& trace_fragment) {
123 // Hand-craft protocol notification message so we can substitute JSON
124 // that we already got as string as a bare object, not a quoted string.
125 std::string message = base::StringPrintf(
126 "{ \"method\": \"%s\", \"params\": { \"%s\": [ %s ] } }",
127 devtools::Tracing::dataCollected::kName,
128 devtools::Tracing::dataCollected::kParamValue,
129 trace_fragment.c_str());
130 SendRawMessage(message);
133 base::debug::TraceOptions DevToolsTracingHandler::TraceOptionsFromString(
134 const std::string& options) {
135 std::vector<std::string> split;
136 std::vector<std::string>::iterator iter;
137 base::debug::TraceOptions ret;
139 base::SplitString(options, ',', &split);
140 for (iter = split.begin(); iter != split.end(); ++iter) {
141 if (*iter == kRecordUntilFull) {
142 ret.record_mode = base::debug::RECORD_UNTIL_FULL;
143 } else if (*iter == kRecordContinuously) {
144 ret.record_mode = base::debug::RECORD_CONTINUOUSLY;
145 } else if (*iter == kRecordAsMuchAsPossible) {
146 ret.record_mode = base::debug::RECORD_AS_MUCH_AS_POSSIBLE;
147 } else if (*iter == kEnableSampling) {
148 ret.enable_sampling = true;
151 return ret;
154 scoped_refptr<DevToolsProtocol::Response>
155 DevToolsTracingHandler::OnStart(
156 scoped_refptr<DevToolsProtocol::Command> command) {
157 is_recording_ = true;
159 std::string categories;
160 base::debug::TraceOptions options;
161 double usage_reporting_interval = 0.0;
163 base::DictionaryValue* params = command->params();
164 if (params) {
165 params->GetString(devtools::Tracing::start::kParamCategories, &categories);
166 std::string options_param;
167 if (params->GetString(devtools::Tracing::start::kParamOptions,
168 &options_param)) {
169 options = TraceOptionsFromString(options_param);
171 params->GetDouble(
172 devtools::Tracing::start::kParamBufferUsageReportingInterval,
173 &usage_reporting_interval);
176 SetupTimer(usage_reporting_interval);
178 // If inspected target is a render process Tracing.start will be handled by
179 // tracing agent in the renderer.
180 if (target_ == Renderer) {
181 TracingController::GetInstance()->EnableRecording(
182 base::debug::CategoryFilter(categories),
183 options,
184 TracingController::EnableRecordingDoneCallback());
185 return NULL;
188 TracingController::GetInstance()->EnableRecording(
189 base::debug::CategoryFilter(categories),
190 options,
191 base::Bind(&DevToolsTracingHandler::OnRecordingEnabled,
192 weak_factory_.GetWeakPtr(),
193 command));
194 return command->AsyncResponsePromise();
197 void DevToolsTracingHandler::SetupTimer(double usage_reporting_interval) {
198 if (usage_reporting_interval == 0) return;
200 if (usage_reporting_interval < kMinimumReportingInterval)
201 usage_reporting_interval = kMinimumReportingInterval;
203 base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
204 std::ceil(usage_reporting_interval));
205 buffer_usage_poll_timer_.reset(new base::Timer(
206 FROM_HERE,
207 interval,
208 base::Bind(
209 base::IgnoreResult(&TracingController::GetTraceBufferPercentFull),
210 base::Unretained(TracingController::GetInstance()),
211 base::Bind(&DevToolsTracingHandler::OnBufferUsage,
212 weak_factory_.GetWeakPtr())),
213 true));
214 buffer_usage_poll_timer_->Reset();
217 void DevToolsTracingHandler::OnRecordingEnabled(
218 scoped_refptr<DevToolsProtocol::Command> command) {
219 SendAsyncResponse(command->SuccessResponse(NULL));
222 void DevToolsTracingHandler::OnBufferUsage(float usage) {
223 base::DictionaryValue* params = new base::DictionaryValue();
224 params->SetDouble(devtools::Tracing::bufferUsage::kParamValue, usage);
225 SendNotification(devtools::Tracing::bufferUsage::kName, params);
228 scoped_refptr<DevToolsProtocol::Response>
229 DevToolsTracingHandler::OnEnd(
230 scoped_refptr<DevToolsProtocol::Command> command) {
231 DisableRecording(
232 base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult,
233 weak_factory_.GetWeakPtr()));
234 return command->SuccessResponse(NULL);
237 void DevToolsTracingHandler::DisableRecording(
238 const TracingController::TracingFileResultCallback& callback) {
239 is_recording_ = false;
240 buffer_usage_poll_timer_.reset();
241 TracingController::GetInstance()->DisableRecording(base::FilePath(),
242 callback);
245 void DevToolsTracingHandler::OnClientDetached() {
246 if (is_recording_)
247 DisableRecording();
250 scoped_refptr<DevToolsProtocol::Response>
251 DevToolsTracingHandler::OnGetCategories(
252 scoped_refptr<DevToolsProtocol::Command> command) {
253 TracingController::GetInstance()->GetCategories(
254 base::Bind(&DevToolsTracingHandler::OnCategoriesReceived,
255 weak_factory_.GetWeakPtr(),
256 command));
257 return command->AsyncResponsePromise();
260 void DevToolsTracingHandler::OnCategoriesReceived(
261 scoped_refptr<DevToolsProtocol::Command> command,
262 const std::set<std::string>& category_set) {
263 base::DictionaryValue* response = new base::DictionaryValue;
264 base::ListValue* category_list = new base::ListValue;
265 for (std::set<std::string>::const_iterator it = category_set.begin();
266 it != category_set.end(); ++it) {
267 category_list->AppendString(*it);
270 response->Set(devtools::Tracing::getCategories::kResponseCategories,
271 category_list);
272 SendAsyncResponse(command->SuccessResponse(response));
275 void DevToolsTracingHandler::OnTracingStarted(
276 scoped_refptr<DevToolsProtocol::Notification> notification) {
277 if (is_recording_)
278 return;
279 is_recording_ = true;
281 SetupTimer(kDefaultReportingInterval);
283 TracingController::GetInstance()->EnableRecording(
284 base::debug::CategoryFilter(kDefaultCategories),
285 base::debug::TraceOptions(),
286 TracingController::EnableRecordingDoneCallback());
289 void DevToolsTracingHandler::OnTracingStopped(
290 scoped_refptr<DevToolsProtocol::Notification> notification) {
291 if (!is_recording_)
292 return;
293 is_recording_ = false;
294 DisableRecording(
295 base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult,
296 weak_factory_.GetWeakPtr()));
300 } // namespace content