[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / devtools / protocol / tracing_handler.cc
blob3518ed5e9962112041960417cc7a86f3d03cf37d
1 // Copyright 2014 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/protocol/tracing_handler.h"
7 #include <cmath>
9 #include "base/bind.h"
10 #include "base/format_macros.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h"
14 #include "base/timer/timer.h"
15 #include "base/trace_event/memory_dump_manager.h"
16 #include "base/trace_event/trace_event_impl.h"
17 #include "components/tracing/trace_config_file.h"
18 #include "content/browser/devtools/devtools_io_context.h"
20 namespace content {
21 namespace devtools {
22 namespace tracing {
24 using Response = DevToolsProtocolClient::Response;
26 namespace {
28 const double kMinimumReportingInterval = 250.0;
30 class DevToolsTraceSinkProxy : public TracingController::TraceDataSink {
31 public:
32 explicit DevToolsTraceSinkProxy(base::WeakPtr<TracingHandler> handler)
33 : tracing_handler_(handler) {}
35 void AddTraceChunk(const std::string& chunk) override {
36 if (TracingHandler* h = tracing_handler_.get())
37 h->OnTraceDataCollected(chunk);
39 void Close() override {
40 if (TracingHandler* h = tracing_handler_.get())
41 h->OnTraceComplete();
44 private:
45 ~DevToolsTraceSinkProxy() override {}
47 base::WeakPtr<TracingHandler> tracing_handler_;
50 class DevToolsStreamTraceSink : public TracingController::TraceDataSink {
51 public:
52 explicit DevToolsStreamTraceSink(
53 base::WeakPtr<TracingHandler> handler,
54 const scoped_refptr<DevToolsIOContext::Stream>& stream)
55 : stream_(stream),
56 tracing_handler_(handler),
57 first_chunk_(true) {}
59 void AddTraceChunk(const std::string& chunk) override {
60 // FIXME: change interface to pass chunks as refcounted strings.
61 scoped_refptr<base::RefCountedString> ref_counted_chunk
62 = new base::RefCountedString();
63 std::string prefix = first_chunk_ ? "[" : ",";
64 ref_counted_chunk->data() = prefix + chunk;
65 first_chunk_ = false;
66 stream_->Append(ref_counted_chunk);
69 void Close() override {
70 if (TracingHandler* h = tracing_handler_.get()) {
71 std::string suffix = "]";
72 stream_->Append(base::RefCountedString::TakeString(&suffix));
73 h->OnTraceToStreamComplete(stream_->handle());
77 private:
78 ~DevToolsStreamTraceSink() override {}
80 scoped_refptr<DevToolsIOContext::Stream> stream_;
81 base::WeakPtr<TracingHandler> tracing_handler_;
82 bool first_chunk_;
85 } // namespace
87 TracingHandler::TracingHandler(TracingHandler::Target target,
88 DevToolsIOContext* io_context)
89 : target_(target),
90 io_context_(io_context),
91 did_initiate_recording_(false),
92 return_as_stream_(false),
93 weak_factory_(this) {}
95 TracingHandler::~TracingHandler() {
98 void TracingHandler::SetClient(scoped_ptr<Client> client) {
99 client_.swap(client);
102 void TracingHandler::Detached() {
103 if (did_initiate_recording_)
104 DisableRecording(scoped_refptr<TracingController::TraceDataSink>());
107 void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) {
108 // Hand-craft protocol notification message so we can substitute JSON
109 // that we already got as string as a bare object, not a quoted string.
110 std::string message(
111 "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": [");
112 const size_t messageSuffixSize = 10;
113 message.reserve(message.size() + trace_fragment.size() + messageSuffixSize);
114 message += trace_fragment;
115 message += "] } }";
116 client_->SendRawMessage(message);
119 void TracingHandler::OnTraceComplete() {
120 client_->TracingComplete(TracingCompleteParams::Create());
123 void TracingHandler::OnTraceToStreamComplete(const std::string& stream_handle) {
124 client_->TracingComplete(
125 TracingCompleteParams::Create()->set_stream(stream_handle));
128 Response TracingHandler::Start(DevToolsCommandId command_id,
129 const std::string* categories,
130 const std::string* options,
131 const double* buffer_usage_reporting_interval,
132 const std::string* transfer_mode) {
133 if (IsRecording())
134 return Response::InternalError("Tracing is already started");
136 did_initiate_recording_ = true;
137 return_as_stream_ =
138 transfer_mode && *transfer_mode == start::kTransferModeReturnAsStream;
139 base::trace_event::TraceConfig trace_config(
140 categories ? *categories : std::string(),
141 options ? *options : std::string());
142 if (buffer_usage_reporting_interval)
143 SetupTimer(*buffer_usage_reporting_interval);
145 // If inspected target is a render process Tracing.start will be handled by
146 // tracing agent in the renderer.
147 if (target_ == Renderer) {
148 TracingController::GetInstance()->EnableRecording(
149 trace_config,
150 TracingController::EnableRecordingDoneCallback());
151 return Response::FallThrough();
154 TracingController::GetInstance()->EnableRecording(
155 trace_config,
156 base::Bind(&TracingHandler::OnRecordingEnabled,
157 weak_factory_.GetWeakPtr(),
158 command_id));
159 return Response::OK();
162 Response TracingHandler::End(DevToolsCommandId command_id) {
163 // Startup tracing triggered by --trace-config-file is a special case, where
164 // tracing is started automatically upon browser startup and can be stopped
165 // via DevTools.
166 if (!did_initiate_recording_ && !IsStartupTracingActive())
167 return Response::InternalError("Tracing is not started");
169 scoped_refptr<TracingController::TraceDataSink> proxy;
170 if (return_as_stream_) {
171 proxy = new DevToolsStreamTraceSink(
172 weak_factory_.GetWeakPtr(), io_context_->CreateTempFileBackedStream());
173 } else {
174 proxy = new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr());
176 DisableRecording(proxy);
177 // If inspected target is a render process Tracing.end will be handled by
178 // tracing agent in the renderer.
179 return target_ == Renderer ? Response::FallThrough() : Response::OK();
182 Response TracingHandler::GetCategories(DevToolsCommandId command_id) {
183 TracingController::GetInstance()->GetCategories(
184 base::Bind(&TracingHandler::OnCategoriesReceived,
185 weak_factory_.GetWeakPtr(),
186 command_id));
187 return Response::OK();
190 void TracingHandler::OnRecordingEnabled(DevToolsCommandId command_id) {
191 client_->SendStartResponse(command_id, StartResponse::Create());
194 void TracingHandler::OnBufferUsage(float percent_full,
195 size_t approximate_event_count) {
196 // TODO(crbug426117): remove set_value once all clients have switched to
197 // the new interface of the event.
198 client_->BufferUsage(BufferUsageParams::Create()
199 ->set_value(percent_full)
200 ->set_percent_full(percent_full)
201 ->set_event_count(approximate_event_count));
204 void TracingHandler::OnCategoriesReceived(
205 DevToolsCommandId command_id,
206 const std::set<std::string>& category_set) {
207 std::vector<std::string> categories;
208 for (const std::string& category : category_set)
209 categories.push_back(category);
210 client_->SendGetCategoriesResponse(command_id,
211 GetCategoriesResponse::Create()->set_categories(categories));
214 Response TracingHandler::RequestMemoryDump(DevToolsCommandId command_id) {
215 if (!IsRecording())
216 return Response::InternalError("Tracing is not started");
218 base::trace_event::MemoryDumpManager::GetInstance()->RequestGlobalDump(
219 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
220 base::trace_event::MemoryDumpLevelOfDetail::DETAILED,
221 base::Bind(&TracingHandler::OnMemoryDumpFinished,
222 weak_factory_.GetWeakPtr(), command_id));
223 return Response::OK();
226 void TracingHandler::OnMemoryDumpFinished(DevToolsCommandId command_id,
227 uint64 dump_guid,
228 bool success) {
229 client_->SendRequestMemoryDumpResponse(
230 command_id,
231 RequestMemoryDumpResponse::Create()
232 ->set_dump_guid(base::StringPrintf("0x%" PRIx64, dump_guid))
233 ->set_success(success));
236 void TracingHandler::SetupTimer(double usage_reporting_interval) {
237 if (usage_reporting_interval == 0) return;
239 if (usage_reporting_interval < kMinimumReportingInterval)
240 usage_reporting_interval = kMinimumReportingInterval;
242 base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
243 std::ceil(usage_reporting_interval));
244 buffer_usage_poll_timer_.reset(new base::Timer(
245 FROM_HERE, interval,
246 base::Bind(base::IgnoreResult(&TracingController::GetTraceBufferUsage),
247 base::Unretained(TracingController::GetInstance()),
248 base::Bind(&TracingHandler::OnBufferUsage,
249 weak_factory_.GetWeakPtr())),
250 true));
251 buffer_usage_poll_timer_->Reset();
254 void TracingHandler::DisableRecording(
255 const scoped_refptr<TracingController::TraceDataSink>& trace_data_sink) {
256 buffer_usage_poll_timer_.reset();
257 TracingController::GetInstance()->DisableRecording(trace_data_sink);
258 did_initiate_recording_ = false;
261 bool TracingHandler::IsRecording() const {
262 return TracingController::GetInstance()->IsRecording();
265 bool TracingHandler::IsStartupTracingActive() {
266 return ::tracing::TraceConfigFile::GetInstance()->IsEnabled() &&
267 TracingController::GetInstance()->IsRecording();
270 } // namespace tracing
271 } // namespace devtools
272 } // namespace content