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"
10 #include "base/strings/string_split.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/time/time.h"
13 #include "base/timer/timer.h"
14 #include "base/trace_event/trace_event_impl.h"
20 typedef DevToolsProtocolClient::Response Response
;
24 const char kRecordUntilFull
[] = "record-until-full";
25 const char kRecordContinuously
[] = "record-continuously";
26 const char kRecordAsMuchAsPossible
[] = "record-as-much-as-possible";
27 const char kEnableSampling
[] = "enable-sampling";
28 const double kMinimumReportingInterval
= 250.0;
30 class DevToolsTraceSinkProxy
: public TracingController::TraceDataSink
{
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())
45 ~DevToolsTraceSinkProxy() override
{}
47 base::WeakPtr
<TracingHandler
> tracing_handler_
;
52 TracingHandler::TracingHandler(TracingHandler::Target target
)
58 TracingHandler::~TracingHandler() {
61 void TracingHandler::SetClient(scoped_ptr
<Client
> client
) {
65 void TracingHandler::Detached() {
67 DisableRecording(true);
70 void TracingHandler::OnTraceDataCollected(const std::string
& trace_fragment
) {
71 // Hand-craft protocol notification message so we can substitute JSON
72 // that we already got as string as a bare object, not a quoted string.
74 "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": [");
75 const size_t messageSuffixSize
= 10;
76 message
.reserve(message
.size() + trace_fragment
.size() + messageSuffixSize
);
77 message
+= trace_fragment
;
79 client_
->SendRawMessage(message
);
82 void TracingHandler::OnTraceComplete() {
83 client_
->TracingComplete(TracingCompleteParams::Create());
86 Response
TracingHandler::Start(DevToolsCommandId command_id
,
87 const std::string
* categories
,
88 const std::string
* options_str
,
89 const double* buffer_usage_reporting_interval
) {
91 return Response::InternalError("Tracing is already started");
94 base::trace_event::TraceOptions options
= TraceOptionsFromString(options_str
);
95 base::trace_event::CategoryFilter
filter(categories
? *categories
97 if (buffer_usage_reporting_interval
)
98 SetupTimer(*buffer_usage_reporting_interval
);
100 // If inspected target is a render process Tracing.start will be handled by
101 // tracing agent in the renderer.
102 if (target_
== Renderer
) {
103 TracingController::GetInstance()->EnableRecording(
106 TracingController::EnableRecordingDoneCallback());
107 return Response::FallThrough();
110 TracingController::GetInstance()->EnableRecording(
113 base::Bind(&TracingHandler::OnRecordingEnabled
,
114 weak_factory_
.GetWeakPtr(),
116 return Response::OK();
119 Response
TracingHandler::End(DevToolsCommandId command_id
) {
121 return Response::InternalError("Tracing is not started");
123 DisableRecording(false);
124 // If inspected target is a render process Tracing.end will be handled by
125 // tracing agent in the renderer.
126 return target_
== Renderer
? Response::FallThrough() : Response::OK();
129 Response
TracingHandler::GetCategories(DevToolsCommandId command_id
) {
130 TracingController::GetInstance()->GetCategories(
131 base::Bind(&TracingHandler::OnCategoriesReceived
,
132 weak_factory_
.GetWeakPtr(),
134 return Response::OK();
137 void TracingHandler::OnRecordingEnabled(DevToolsCommandId command_id
) {
138 client_
->SendStartResponse(command_id
, StartResponse::Create());
141 void TracingHandler::OnBufferUsage(float percent_full
,
142 size_t approximate_event_count
) {
143 // TODO(crbug426117): remove set_value once all clients have switched to
144 // the new interface of the event.
145 client_
->BufferUsage(BufferUsageParams::Create()
146 ->set_value(percent_full
)
147 ->set_percent_full(percent_full
)
148 ->set_event_count(approximate_event_count
));
151 void TracingHandler::OnCategoriesReceived(
152 DevToolsCommandId command_id
,
153 const std::set
<std::string
>& category_set
) {
154 std::vector
<std::string
> categories
;
155 for (const std::string
& category
: category_set
)
156 categories
.push_back(category
);
157 client_
->SendGetCategoriesResponse(command_id
,
158 GetCategoriesResponse::Create()->set_categories(categories
));
161 base::trace_event::TraceOptions
TracingHandler::TraceOptionsFromString(
162 const std::string
* options
) {
163 base::trace_event::TraceOptions ret
;
167 std::vector
<std::string
> split
;
168 std::vector
<std::string
>::iterator iter
;
170 base::SplitString(*options
, ',', &split
);
171 for (iter
= split
.begin(); iter
!= split
.end(); ++iter
) {
172 if (*iter
== kRecordUntilFull
) {
173 ret
.record_mode
= base::trace_event::RECORD_UNTIL_FULL
;
174 } else if (*iter
== kRecordContinuously
) {
175 ret
.record_mode
= base::trace_event::RECORD_CONTINUOUSLY
;
176 } else if (*iter
== kRecordAsMuchAsPossible
) {
177 ret
.record_mode
= base::trace_event::RECORD_AS_MUCH_AS_POSSIBLE
;
178 } else if (*iter
== kEnableSampling
) {
179 ret
.enable_sampling
= true;
185 void TracingHandler::SetupTimer(double usage_reporting_interval
) {
186 if (usage_reporting_interval
== 0) return;
188 if (usage_reporting_interval
< kMinimumReportingInterval
)
189 usage_reporting_interval
= kMinimumReportingInterval
;
191 base::TimeDelta interval
= base::TimeDelta::FromMilliseconds(
192 std::ceil(usage_reporting_interval
));
193 buffer_usage_poll_timer_
.reset(new base::Timer(
195 base::Bind(base::IgnoreResult(&TracingController::GetTraceBufferUsage
),
196 base::Unretained(TracingController::GetInstance()),
197 base::Bind(&TracingHandler::OnBufferUsage
,
198 weak_factory_
.GetWeakPtr())),
200 buffer_usage_poll_timer_
->Reset();
203 void TracingHandler::DisableRecording(bool abort
) {
204 is_recording_
= false;
205 buffer_usage_poll_timer_
.reset();
206 TracingController::GetInstance()->DisableRecording(
207 abort
? nullptr : new DevToolsTraceSinkProxy(weak_factory_
.GetWeakPtr()));
210 } // namespace tracing
211 } // namespace devtools
212 } // namespace content