OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 #include "content/browser/devtools/protocol/tracing_handler.h" | 5 #include "content/browser/devtools/protocol/tracing_handler.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/format_macros.h" | 10 #include "base/format_macros.h" |
11 #include "base/json/json_writer.h" | 11 #include "base/json/json_writer.h" |
12 #include "base/memory/ref_counted_memory.h" | 12 #include "base/memory/ref_counted_memory.h" |
13 #include "base/strings/string_split.h" | 13 #include "base/strings/string_split.h" |
14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
15 #include "base/time/time.h" | 15 #include "base/time/time.h" |
16 #include "base/timer/timer.h" | 16 #include "base/timer/timer.h" |
17 #include "base/trace_event/memory_dump_manager.h" | 17 #include "base/trace_event/memory_dump_manager.h" |
18 #include "base/trace_event/trace_event_impl.h" | 18 #include "base/trace_event/trace_event_impl.h" |
19 #include "base/trace_event/tracing_agent.h" | 19 #include "base/trace_event/tracing_agent.h" |
20 #include "components/tracing/browser/trace_config_file.h" | 20 #include "components/tracing/browser/trace_config_file.h" |
21 #include "content/browser/devtools/devtools_io_context.h" | 21 #include "content/browser/devtools/devtools_io_context.h" |
22 #include "content/browser/tracing/tracing_controller_impl.h" | 22 #include "content/browser/tracing/tracing_controller_impl.h" |
23 | 23 |
24 namespace content { | 24 namespace content { |
25 namespace devtools { | 25 namespace protocol { |
26 namespace tracing { | |
27 | |
28 using Response = DevToolsProtocolClient::Response; | |
29 | 26 |
30 namespace { | 27 namespace { |
31 | 28 |
32 const double kMinimumReportingInterval = 250.0; | 29 const double kMinimumReportingInterval = 250.0; |
33 | 30 |
34 const char kRecordModeParam[] = "record_mode"; | 31 const char kRecordModeParam[] = "record_mode"; |
35 | 32 |
36 // Convert from camel case to separator + lowercase. | 33 // Convert from camel case to separator + lowercase. |
37 std::string ConvertFromCamelCase(const std::string& in_str, char separator) { | 34 std::string ConvertFromCamelCase(const std::string& in_str, char separator) { |
38 std::string out_str; | 35 std::string out_str; |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 : target_(target), | 121 : target_(target), |
125 io_context_(io_context), | 122 io_context_(io_context), |
126 frame_tree_node_id_(frame_tree_node_id), | 123 frame_tree_node_id_(frame_tree_node_id), |
127 did_initiate_recording_(false), | 124 did_initiate_recording_(false), |
128 return_as_stream_(false), | 125 return_as_stream_(false), |
129 weak_factory_(this) {} | 126 weak_factory_(this) {} |
130 | 127 |
131 TracingHandler::~TracingHandler() { | 128 TracingHandler::~TracingHandler() { |
132 } | 129 } |
133 | 130 |
134 void TracingHandler::SetClient(std::unique_ptr<Client> client) { | 131 void TracingHandler::Wire(UberDispatcher* dispatcher) { |
135 client_.swap(client); | 132 frontend_.reset(new Tracing::Frontend(dispatcher->channel())); |
| 133 Tracing::Dispatcher::wire(dispatcher, this); |
136 } | 134 } |
137 | 135 |
138 void TracingHandler::Detached() { | 136 Response TracingHandler::Disable() { |
139 if (did_initiate_recording_) | 137 if (did_initiate_recording_) |
140 StopTracing(scoped_refptr<TracingController::TraceDataSink>()); | 138 StopTracing(scoped_refptr<TracingController::TraceDataSink>()); |
| 139 return Response::OK(); |
141 } | 140 } |
142 | 141 |
143 void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) { | 142 void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) { |
144 // Hand-craft protocol notification message so we can substitute JSON | 143 // Hand-craft protocol notification message so we can substitute JSON |
145 // that we already got as string as a bare object, not a quoted string. | 144 // that we already got as string as a bare object, not a quoted string. |
146 std::string message( | 145 std::string message( |
147 "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": ["); | 146 "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": ["); |
148 const size_t messageSuffixSize = 10; | 147 const size_t messageSuffixSize = 10; |
149 message.reserve(message.size() + trace_fragment.size() + messageSuffixSize); | 148 message.reserve(message.size() + trace_fragment.size() + messageSuffixSize); |
150 message += trace_fragment; | 149 message += trace_fragment; |
151 message += "] } }"; | 150 message += "] } }"; |
152 client_->SendRawNotification(message); | 151 frontend_->sendRawNotification(message); |
153 } | 152 } |
154 | 153 |
155 void TracingHandler::OnTraceComplete() { | 154 void TracingHandler::OnTraceComplete() { |
156 client_->TracingComplete(TracingCompleteParams::Create()); | 155 frontend_->TracingComplete(); |
157 } | 156 } |
158 | 157 |
159 void TracingHandler::OnTraceToStreamComplete(const std::string& stream_handle) { | 158 void TracingHandler::OnTraceToStreamComplete(const std::string& stream_handle) { |
160 client_->TracingComplete( | 159 frontend_->TracingComplete(stream_handle); |
161 TracingCompleteParams::Create()->set_stream(stream_handle)); | |
162 } | 160 } |
163 | 161 |
164 Response TracingHandler::Start( | 162 void TracingHandler::Start(Maybe<std::string> categories, |
165 DevToolsCommandId command_id, | 163 Maybe<std::string> options, |
166 const std::string* categories, | 164 Maybe<double> buffer_usage_reporting_interval, |
167 const std::string* options, | 165 Maybe<std::string> transfer_mode, |
168 const double* buffer_usage_reporting_interval, | 166 Maybe<Tracing::TraceConfig> config, |
169 const std::string* transfer_mode, | 167 std::unique_ptr<StartCallback> callback) { |
170 const std::unique_ptr<base::DictionaryValue>& config) { | 168 bool return_as_stream = transfer_mode.fromMaybe("") == |
| 169 Tracing::Start::TransferModeEnum::ReturnAsStream; |
171 if (IsTracing()) { | 170 if (IsTracing()) { |
172 if (!did_initiate_recording_ && IsStartupTracingActive()) { | 171 if (!did_initiate_recording_ && IsStartupTracingActive()) { |
173 // If tracing is already running because it was initiated by startup | 172 // If tracing is already running because it was initiated by startup |
174 // tracing, honor the transfer mode update, as that's the only way | 173 // tracing, honor the transfer mode update, as that's the only way |
175 // for the client to communicate it. | 174 // for the client to communicate it. |
176 return_as_stream_ = | 175 return_as_stream_ = return_as_stream; |
177 transfer_mode && *transfer_mode == start::kTransferModeReturnAsStream; | |
178 } | 176 } |
179 return Response::InternalError("Tracing is already started"); | 177 callback->sendFailure(Response::Error("Tracing is already started")); |
| 178 return; |
180 } | 179 } |
181 | 180 |
182 if (config && (categories || options)) { | 181 if (config.isJust() && (categories.isJust() || options.isJust())) { |
183 return Response::InternalError( | 182 callback->sendFailure(Response::InvalidParams( |
184 "Either trace config (preferred), or categories+options should be " | 183 "Either trace config (preferred), or categories+options should be " |
185 "specified, but not both."); | 184 "specified, but not both.")); |
| 185 return; |
186 } | 186 } |
187 | 187 |
188 did_initiate_recording_ = true; | 188 did_initiate_recording_ = true; |
189 return_as_stream_ = | 189 return_as_stream_ = return_as_stream; |
190 transfer_mode && *transfer_mode == start::kTransferModeReturnAsStream; | 190 if (buffer_usage_reporting_interval.isJust()) |
191 if (buffer_usage_reporting_interval) | 191 SetupTimer(buffer_usage_reporting_interval.fromJust()); |
192 SetupTimer(*buffer_usage_reporting_interval); | |
193 | 192 |
194 base::trace_event::TraceConfig trace_config; | 193 base::trace_event::TraceConfig trace_config; |
195 if (config) { | 194 if (config.isJust()) { |
196 trace_config = GetTraceConfigFromDevToolsConfig(*config); | 195 std::unique_ptr<base::Value> value = |
197 } else if (categories || options) { | 196 protocol::toBaseValue(config.fromJust()->serialize().get(), 1000); |
| 197 if (value && value->IsType(base::Value::TYPE_DICTIONARY)) { |
| 198 trace_config = GetTraceConfigFromDevToolsConfig( |
| 199 *static_cast<base::DictionaryValue*>(value.get())); |
| 200 } |
| 201 } else if (categories.isJust() || options.isJust()) { |
198 trace_config = base::trace_event::TraceConfig( | 202 trace_config = base::trace_event::TraceConfig( |
199 categories ? *categories : std::string(), | 203 categories.fromMaybe(""), options.fromMaybe("")); |
200 options ? *options : std::string()); | |
201 } | 204 } |
202 | 205 |
203 // If inspected target is a render process Tracing.start will be handled by | 206 // If inspected target is a render process Tracing.start will be handled by |
204 // tracing agent in the renderer. | 207 // tracing agent in the renderer. |
| 208 if (target_ == Renderer) |
| 209 callback->fallThrough(); |
| 210 |
205 TracingController::GetInstance()->StartTracing( | 211 TracingController::GetInstance()->StartTracing( |
206 trace_config, | 212 trace_config, |
207 base::Bind(&TracingHandler::OnRecordingEnabled, | 213 base::Bind(&TracingHandler::OnRecordingEnabled, |
208 weak_factory_.GetWeakPtr(), | 214 weak_factory_.GetWeakPtr(), |
209 command_id)); | 215 base::Passed(std::move(callback)))); |
210 | |
211 return target_ == Renderer ? Response::FallThrough() : Response::OK(); | |
212 } | 216 } |
213 | 217 |
214 Response TracingHandler::End(DevToolsCommandId command_id) { | 218 void TracingHandler::End(std::unique_ptr<EndCallback> callback) { |
215 // Startup tracing triggered by --trace-config-file is a special case, where | 219 // Startup tracing triggered by --trace-config-file is a special case, where |
216 // tracing is started automatically upon browser startup and can be stopped | 220 // tracing is started automatically upon browser startup and can be stopped |
217 // via DevTools. | 221 // via DevTools. |
218 if (!did_initiate_recording_ && !IsStartupTracingActive()) | 222 if (!did_initiate_recording_ && !IsStartupTracingActive()) { |
219 return Response::InternalError("Tracing is not started"); | 223 callback->sendFailure(Response::Error("Tracing is not started")); |
| 224 return; |
| 225 } |
220 | 226 |
221 scoped_refptr<TracingController::TraceDataSink> sink; | 227 scoped_refptr<TracingController::TraceDataSink> sink; |
222 if (return_as_stream_) { | 228 if (return_as_stream_) { |
223 sink = TracingControllerImpl::CreateJSONSink(new DevToolsStreamEndpoint( | 229 sink = TracingControllerImpl::CreateJSONSink(new DevToolsStreamEndpoint( |
224 weak_factory_.GetWeakPtr(), io_context_->CreateTempFileBackedStream())); | 230 weak_factory_.GetWeakPtr(), io_context_->CreateTempFileBackedStream())); |
225 } else { | 231 } else { |
226 sink = new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr()); | 232 sink = new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr()); |
227 } | 233 } |
228 StopTracing(sink); | 234 StopTracing(sink); |
229 // If inspected target is a render process Tracing.end will be handled by | 235 // If inspected target is a render process Tracing.end will be handled by |
230 // tracing agent in the renderer. | 236 // tracing agent in the renderer. |
231 return target_ == Renderer ? Response::FallThrough() : Response::OK(); | 237 if (target_ == Renderer) |
| 238 callback->fallThrough(); |
| 239 else |
| 240 callback->sendSuccess(); |
232 } | 241 } |
233 | 242 |
234 Response TracingHandler::GetCategories(DevToolsCommandId command_id) { | 243 void TracingHandler::GetCategories( |
| 244 std::unique_ptr<GetCategoriesCallback> callback) { |
235 TracingController::GetInstance()->GetCategories( | 245 TracingController::GetInstance()->GetCategories( |
236 base::Bind(&TracingHandler::OnCategoriesReceived, | 246 base::Bind(&TracingHandler::OnCategoriesReceived, |
237 weak_factory_.GetWeakPtr(), | 247 weak_factory_.GetWeakPtr(), |
238 command_id)); | 248 base::Passed(std::move(callback)))); |
239 return Response::OK(); | |
240 } | 249 } |
241 | 250 |
242 void TracingHandler::OnRecordingEnabled(DevToolsCommandId command_id) { | 251 void TracingHandler::OnRecordingEnabled( |
| 252 std::unique_ptr<StartCallback> callback) { |
243 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 253 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), |
244 "TracingStartedInBrowser", TRACE_EVENT_SCOPE_THREAD, | 254 "TracingStartedInBrowser", TRACE_EVENT_SCOPE_THREAD, |
245 "frameTreeNodeId", frame_tree_node_id_); | 255 "frameTreeNodeId", frame_tree_node_id_); |
246 if (target_ != Renderer) | 256 if (target_ != Renderer) |
247 client_->SendStartResponse(command_id, StartResponse::Create()); | 257 callback->sendSuccess(); |
248 } | 258 } |
249 | 259 |
250 void TracingHandler::OnBufferUsage(float percent_full, | 260 void TracingHandler::OnBufferUsage(float percent_full, |
251 size_t approximate_event_count) { | 261 size_t approximate_event_count) { |
252 // TODO(crbug426117): remove set_value once all clients have switched to | 262 // TODO(crbug426117): remove set_value once all clients have switched to |
253 // the new interface of the event. | 263 // the new interface of the event. |
254 client_->BufferUsage(BufferUsageParams::Create() | 264 frontend_->BufferUsage(percent_full, percent_full, approximate_event_count); |
255 ->set_value(percent_full) | |
256 ->set_percent_full(percent_full) | |
257 ->set_event_count(approximate_event_count)); | |
258 } | 265 } |
259 | 266 |
260 void TracingHandler::OnCategoriesReceived( | 267 void TracingHandler::OnCategoriesReceived( |
261 DevToolsCommandId command_id, | 268 std::unique_ptr<GetCategoriesCallback> callback, |
262 const std::set<std::string>& category_set) { | 269 const std::set<std::string>& category_set) { |
263 std::vector<std::string> categories; | 270 std::unique_ptr<protocol::Array<std::string>> categories = |
| 271 protocol::Array<std::string>::create(); |
264 for (const std::string& category : category_set) | 272 for (const std::string& category : category_set) |
265 categories.push_back(category); | 273 categories->addItem(category); |
266 client_->SendGetCategoriesResponse(command_id, | 274 callback->sendSuccess(std::move(categories)); |
267 GetCategoriesResponse::Create()->set_categories(categories)); | |
268 } | 275 } |
269 | 276 |
270 Response TracingHandler::RequestMemoryDump(DevToolsCommandId command_id) { | 277 void TracingHandler::RequestMemoryDump( |
271 if (!IsTracing()) | 278 std::unique_ptr<RequestMemoryDumpCallback> callback) { |
272 return Response::InternalError("Tracing is not started"); | 279 if (!IsTracing()) { |
| 280 callback->sendFailure(Response::Error("Tracing is not started")); |
| 281 return; |
| 282 } |
273 | 283 |
274 base::trace_event::MemoryDumpManager::GetInstance()->RequestGlobalDump( | 284 base::trace_event::MemoryDumpManager::GetInstance()->RequestGlobalDump( |
275 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED, | 285 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED, |
276 base::trace_event::MemoryDumpLevelOfDetail::DETAILED, | 286 base::trace_event::MemoryDumpLevelOfDetail::DETAILED, |
277 base::Bind(&TracingHandler::OnMemoryDumpFinished, | 287 base::Bind(&TracingHandler::OnMemoryDumpFinished, |
278 weak_factory_.GetWeakPtr(), command_id)); | 288 weak_factory_.GetWeakPtr(), |
279 return Response::OK(); | 289 base::Passed(std::move(callback)))); |
280 } | 290 } |
281 | 291 |
282 void TracingHandler::OnMemoryDumpFinished(DevToolsCommandId command_id, | 292 void TracingHandler::OnMemoryDumpFinished( |
283 uint64_t dump_guid, | 293 std::unique_ptr<RequestMemoryDumpCallback> callback, |
284 bool success) { | 294 uint64_t dump_guid, |
285 client_->SendRequestMemoryDumpResponse( | 295 bool success) { |
286 command_id, | 296 callback->sendSuccess(base::StringPrintf("0x%" PRIx64, dump_guid), success); |
287 RequestMemoryDumpResponse::Create() | |
288 ->set_dump_guid(base::StringPrintf("0x%" PRIx64, dump_guid)) | |
289 ->set_success(success)); | |
290 } | 297 } |
291 | 298 |
292 Response TracingHandler::RecordClockSyncMarker(const std::string& sync_id) { | 299 Response TracingHandler::RecordClockSyncMarker(const std::string& sync_id) { |
293 if (!IsTracing()) | 300 if (!IsTracing()) |
294 return Response::InternalError("Tracing is not started"); | 301 return Response::Error("Tracing is not started"); |
295 | 302 |
296 TracingControllerImpl::GetInstance()->RecordClockSyncMarker( | 303 TracingControllerImpl::GetInstance()->RecordClockSyncMarker( |
297 sync_id, | 304 sync_id, |
298 base::trace_event::TracingAgent::RecordClockSyncMarkerCallback()); | 305 base::trace_event::TracingAgent::RecordClockSyncMarkerCallback()); |
299 | 306 |
300 return Response::OK(); | 307 return Response::OK(); |
301 } | 308 } |
302 | 309 |
303 void TracingHandler::SetupTimer(double usage_reporting_interval) { | 310 void TracingHandler::SetupTimer(double usage_reporting_interval) { |
304 if (usage_reporting_interval == 0) return; | 311 if (usage_reporting_interval == 0) return; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 static_cast<base::DictionaryValue*>(value.release())); | 350 static_cast<base::DictionaryValue*>(value.release())); |
344 | 351 |
345 std::string mode; | 352 std::string mode; |
346 if (tracing_dict->GetString(kRecordModeParam, &mode)) | 353 if (tracing_dict->GetString(kRecordModeParam, &mode)) |
347 tracing_dict->SetString(kRecordModeParam, ConvertFromCamelCase(mode, '-')); | 354 tracing_dict->SetString(kRecordModeParam, ConvertFromCamelCase(mode, '-')); |
348 | 355 |
349 return base::trace_event::TraceConfig(*tracing_dict); | 356 return base::trace_event::TraceConfig(*tracing_dict); |
350 } | 357 } |
351 | 358 |
352 } // namespace tracing | 359 } // namespace tracing |
353 } // namespace devtools | 360 } // namespace protocol |
354 } // namespace content | |
OLD | NEW |