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"
10 #include "base/callback.h"
11 #include "base/file_util.h"
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/location.h"
15 #include "base/memory/ref_counted_memory.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/time/time.h"
19 #include "base/timer/timer.h"
20 #include "base/values.h"
21 #include "content/browser/devtools/devtools_http_handler_impl.h"
22 #include "content/browser/devtools/devtools_protocol_constants.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/tracing_controller.h"
30 const char kRecordUntilFull[] = "record-until-full";
31 const char kRecordContinuously[] = "record-continuously";
32 const char kEnableSampling[] = "enable-sampling";
35 const base::FilePath& path,
36 const base::Callback<void(const scoped_refptr<base::RefCountedString>&)>
38 std::string trace_data;
39 if (!base::ReadFileToString(path, &trace_data))
40 LOG(ERROR) << "Failed to read file: " << path.value();
41 base::DeleteFile(path, false);
42 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
43 base::Bind(callback, make_scoped_refptr(
44 base::RefCountedString::TakeString(&trace_data))));
49 DevToolsTracingHandler::DevToolsTracingHandler()
50 : weak_factory_(this) {
51 RegisterCommandHandler(devtools::Tracing::start::kName,
52 base::Bind(&DevToolsTracingHandler::OnStart,
53 base::Unretained(this)));
54 RegisterCommandHandler(devtools::Tracing::end::kName,
55 base::Bind(&DevToolsTracingHandler::OnEnd,
56 base::Unretained(this)));
59 DevToolsTracingHandler::~DevToolsTracingHandler() {
62 void DevToolsTracingHandler::BeginReadingRecordingResult(
63 const base::FilePath& path) {
64 BrowserThread::PostTask(
65 BrowserThread::FILE, FROM_HERE,
66 base::Bind(&ReadFile, path,
67 base::Bind(&DevToolsTracingHandler::ReadRecordingResult,
68 weak_factory_.GetWeakPtr())));
71 void DevToolsTracingHandler::ReadRecordingResult(
72 const scoped_refptr<base::RefCountedString>& trace_data) {
73 if (trace_data->data().size()) {
74 scoped_ptr<base::Value> trace_value(base::JSONReader::Read(
76 base::DictionaryValue* dictionary = NULL;
77 bool ok = trace_value->GetAsDictionary(&dictionary);
79 base::ListValue* list = NULL;
80 ok = dictionary->GetList("traceEvents", &list);
83 for (size_t i = 0; i < list->GetSize(); ++i) {
85 base::Value* item_value;
86 list->Get(i, &item_value);
87 base::JSONWriter::Write(item_value, &item);
92 OnTraceDataCollected(buffer);
97 OnTraceDataCollected(buffer);
100 SendNotification(devtools::Tracing::tracingComplete::kName, NULL);
103 void DevToolsTracingHandler::OnTraceDataCollected(
104 const std::string& trace_fragment) {
105 // Hand-craft protocol notification message so we can substitute JSON
106 // that we already got as string as a bare object, not a quoted string.
107 std::string message = base::StringPrintf(
108 "{ \"method\": \"%s\", \"params\": { \"%s\": [ %s ] } }",
109 devtools::Tracing::dataCollected::kName,
110 devtools::Tracing::dataCollected::kParamValue,
111 trace_fragment.c_str());
112 SendRawMessage(message);
115 TracingController::Options DevToolsTracingHandler::TraceOptionsFromString(
116 const std::string& options) {
117 std::vector<std::string> split;
118 std::vector<std::string>::iterator iter;
121 base::SplitString(options, ',', &split);
122 for (iter = split.begin(); iter != split.end(); ++iter) {
123 if (*iter == kRecordUntilFull) {
124 ret &= ~TracingController::RECORD_CONTINUOUSLY;
125 } else if (*iter == kRecordContinuously) {
126 ret |= TracingController::RECORD_CONTINUOUSLY;
127 } else if (*iter == kEnableSampling) {
128 ret |= TracingController::ENABLE_SAMPLING;
131 return static_cast<TracingController::Options>(ret);
134 scoped_refptr<DevToolsProtocol::Response>
135 DevToolsTracingHandler::OnStart(
136 scoped_refptr<DevToolsProtocol::Command> command) {
137 std::string categories;
138 base::DictionaryValue* params = command->params();
140 params->GetString(devtools::Tracing::start::kParamCategories, &categories);
142 TracingController::Options options = TracingController::DEFAULT_OPTIONS;
143 if (params && params->HasKey(devtools::Tracing::start::kParamOptions)) {
144 std::string options_param;
145 params->GetString(devtools::Tracing::start::kParamOptions, &options_param);
146 options = TraceOptionsFromString(options_param);
149 if (params && params->HasKey(
150 devtools::Tracing::start::kParamBufferUsageReportingInterval)) {
151 double usage_reporting_interval = 0.0;
153 devtools::Tracing::start::kParamBufferUsageReportingInterval,
154 &usage_reporting_interval);
155 if (usage_reporting_interval > 0) {
156 base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
157 std::ceil(usage_reporting_interval));
158 buffer_usage_poll_timer_.reset(new base::Timer(
162 base::IgnoreResult(&TracingController::GetTraceBufferPercentFull),
163 base::Unretained(TracingController::GetInstance()),
164 base::Bind(&DevToolsTracingHandler::OnBufferUsage,
165 weak_factory_.GetWeakPtr())),
167 buffer_usage_poll_timer_->Reset();
171 TracingController::GetInstance()->EnableRecording(
172 categories, options, TracingController::EnableRecordingDoneCallback());
177 void DevToolsTracingHandler::OnBufferUsage(float usage) {
178 base::DictionaryValue* params = new base::DictionaryValue();
179 params->SetDouble(devtools::Tracing::bufferUsage::kParamValue, usage);
180 SendNotification(devtools::Tracing::bufferUsage::kName, params);
183 scoped_refptr<DevToolsProtocol::Response>
184 DevToolsTracingHandler::OnEnd(
185 scoped_refptr<DevToolsProtocol::Command> command) {
186 buffer_usage_poll_timer_.reset();
187 TracingController::GetInstance()->DisableRecording(
189 base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult,
190 weak_factory_.GetWeakPtr()));
191 return command->SuccessResponse(NULL);
194 } // namespace content