Chromium Code Reviews| 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 void TracingHandler::Detached() { |
| 137 Disable(); | |
| 138 } | |
| 139 | |
| 140 Response TracingHandler::Disable() { | |
| 139 if (did_initiate_recording_) | 141 if (did_initiate_recording_) |
| 140 StopTracing(scoped_refptr<TracingController::TraceDataSink>()); | 142 StopTracing(scoped_refptr<TracingController::TraceDataSink>()); |
| 143 return Response::OK(); | |
| 141 } | 144 } |
| 142 | 145 |
| 143 void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) { | 146 void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) { |
| 144 // Hand-craft protocol notification message so we can substitute JSON | 147 // 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. | 148 // that we already got as string as a bare object, not a quoted string. |
| 146 std::string message( | 149 std::string message( |
| 147 "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": ["); | 150 "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": ["); |
| 148 const size_t messageSuffixSize = 10; | 151 const size_t messageSuffixSize = 10; |
| 149 message.reserve(message.size() + trace_fragment.size() + messageSuffixSize); | 152 message.reserve(message.size() + trace_fragment.size() + messageSuffixSize); |
| 150 message += trace_fragment; | 153 message += trace_fragment; |
| 151 message += "] } }"; | 154 message += "] } }"; |
| 152 client_->SendRawNotification(message); | 155 frontend_->sendRawNotification(message); |
| 153 } | 156 } |
| 154 | 157 |
| 155 void TracingHandler::OnTraceComplete() { | 158 void TracingHandler::OnTraceComplete() { |
| 156 client_->TracingComplete(TracingCompleteParams::Create()); | 159 frontend_->TracingComplete(); |
| 157 } | 160 } |
| 158 | 161 |
| 159 void TracingHandler::OnTraceToStreamComplete(const std::string& stream_handle) { | 162 void TracingHandler::OnTraceToStreamComplete(const std::string& stream_handle) { |
| 160 client_->TracingComplete( | 163 frontend_->TracingComplete(stream_handle); |
| 161 TracingCompleteParams::Create()->set_stream(stream_handle)); | |
| 162 } | 164 } |
| 163 | 165 |
| 164 Response TracingHandler::Start( | 166 void TracingHandler::Start(Maybe<std::string> categories, |
| 165 DevToolsCommandId command_id, | 167 Maybe<std::string> options, |
| 166 const std::string* categories, | 168 Maybe<double> buffer_usage_reporting_interval, |
| 167 const std::string* options, | 169 Maybe<std::string> transfer_mode, |
| 168 const double* buffer_usage_reporting_interval, | 170 Maybe<Tracing::TraceConfig> config, |
| 169 const std::string* transfer_mode, | 171 std::unique_ptr<StartCallback> callback) { |
| 170 const std::unique_ptr<base::DictionaryValue>& config) { | 172 bool return_as_stream = transfer_mode.fromMaybe("") == |
| 173 Tracing::Start::TransferModeEnum::ReturnAsStream; | |
| 171 if (IsTracing()) { | 174 if (IsTracing()) { |
| 172 if (!did_initiate_recording_ && IsStartupTracingActive()) { | 175 if (!did_initiate_recording_ && IsStartupTracingActive()) { |
| 173 // If tracing is already running because it was initiated by startup | 176 // If tracing is already running because it was initiated by startup |
| 174 // tracing, honor the transfer mode update, as that's the only way | 177 // tracing, honor the transfer mode update, as that's the only way |
| 175 // for the client to communicate it. | 178 // for the client to communicate it. |
| 176 return_as_stream_ = | 179 return_as_stream_ = return_as_stream; |
| 177 transfer_mode && *transfer_mode == start::kTransferModeReturnAsStream; | |
| 178 } | 180 } |
| 179 return Response::InternalError("Tracing is already started"); | 181 callback->sendFailure(Response::Error("Tracing is already started")); |
| 182 return; | |
| 180 } | 183 } |
| 181 | 184 |
| 182 if (config && (categories || options)) { | 185 if (config.isJust() && (categories.isJust() || options.isJust())) { |
| 183 return Response::InternalError( | 186 callback->sendFailure(Response::Error( |
|
caseq
2016/11/15 18:33:59
InvalidParams
dgozman
2016/11/17 21:51:07
Done.
| |
| 184 "Either trace config (preferred), or categories+options should be " | 187 "Either trace config (preferred), or categories+options should be " |
| 185 "specified, but not both."); | 188 "specified, but not both.")); |
| 189 return; | |
| 186 } | 190 } |
| 187 | 191 |
| 188 did_initiate_recording_ = true; | 192 did_initiate_recording_ = true; |
| 189 return_as_stream_ = | 193 return_as_stream_ = return_as_stream; |
| 190 transfer_mode && *transfer_mode == start::kTransferModeReturnAsStream; | 194 if (buffer_usage_reporting_interval.isJust()) |
| 191 if (buffer_usage_reporting_interval) | 195 SetupTimer(buffer_usage_reporting_interval.fromJust()); |
| 192 SetupTimer(*buffer_usage_reporting_interval); | |
| 193 | 196 |
| 194 base::trace_event::TraceConfig trace_config; | 197 base::trace_event::TraceConfig trace_config; |
| 195 if (config) { | 198 if (config.isJust()) { |
| 196 trace_config = GetTraceConfigFromDevToolsConfig(*config); | 199 std::unique_ptr<base::Value> value = |
| 197 } else if (categories || options) { | 200 protocol::toBaseValue(config.fromJust()->serialize().get(), 1000); |
| 201 if (value && value->IsType(base::Value::TYPE_DICTIONARY)) { | |
| 202 trace_config = GetTraceConfigFromDevToolsConfig( | |
| 203 *static_cast<base::DictionaryValue*>(value.get())); | |
| 204 } | |
| 205 } else if (categories.isJust() || options.isJust()) { | |
| 198 trace_config = base::trace_event::TraceConfig( | 206 trace_config = base::trace_event::TraceConfig( |
| 199 categories ? *categories : std::string(), | 207 categories.fromMaybe(std::string()), |
|
caseq
2016/11/15 18:33:59
""
dgozman
2016/11/17 21:51:07
Done.
| |
| 200 options ? *options : std::string()); | 208 options.fromMaybe(std::string())); |
|
caseq
2016/11/15 18:33:59
""
| |
| 201 } | 209 } |
| 202 | 210 |
| 203 // If inspected target is a render process Tracing.start will be handled by | 211 // If inspected target is a render process Tracing.start will be handled by |
| 204 // tracing agent in the renderer. | 212 // tracing agent in the renderer. |
| 213 if (target_ == Renderer) | |
| 214 callback->fallThrough(); | |
| 215 | |
| 205 TracingController::GetInstance()->StartTracing( | 216 TracingController::GetInstance()->StartTracing( |
| 206 trace_config, | 217 trace_config, |
| 207 base::Bind(&TracingHandler::OnRecordingEnabled, | 218 base::Bind(&TracingHandler::OnRecordingEnabled, |
| 208 weak_factory_.GetWeakPtr(), | 219 weak_factory_.GetWeakPtr(), |
| 209 command_id)); | 220 base::Passed(std::move(callback)))); |
| 210 | |
| 211 return target_ == Renderer ? Response::FallThrough() : Response::OK(); | |
| 212 } | 221 } |
| 213 | 222 |
| 214 Response TracingHandler::End(DevToolsCommandId command_id) { | 223 void TracingHandler::End(std::unique_ptr<EndCallback> callback) { |
| 215 // Startup tracing triggered by --trace-config-file is a special case, where | 224 // Startup tracing triggered by --trace-config-file is a special case, where |
| 216 // tracing is started automatically upon browser startup and can be stopped | 225 // tracing is started automatically upon browser startup and can be stopped |
| 217 // via DevTools. | 226 // via DevTools. |
| 218 if (!did_initiate_recording_ && !IsStartupTracingActive()) | 227 if (!did_initiate_recording_ && !IsStartupTracingActive()) { |
| 219 return Response::InternalError("Tracing is not started"); | 228 callback->sendFailure(Response::Error("Tracing is not started")); |
| 229 return; | |
| 230 } | |
| 220 | 231 |
| 221 scoped_refptr<TracingController::TraceDataSink> sink; | 232 scoped_refptr<TracingController::TraceDataSink> sink; |
| 222 if (return_as_stream_) { | 233 if (return_as_stream_) { |
| 223 sink = TracingControllerImpl::CreateJSONSink(new DevToolsStreamEndpoint( | 234 sink = TracingControllerImpl::CreateJSONSink(new DevToolsStreamEndpoint( |
| 224 weak_factory_.GetWeakPtr(), io_context_->CreateTempFileBackedStream())); | 235 weak_factory_.GetWeakPtr(), io_context_->CreateTempFileBackedStream())); |
| 225 } else { | 236 } else { |
| 226 sink = new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr()); | 237 sink = new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr()); |
| 227 } | 238 } |
| 228 StopTracing(sink); | 239 StopTracing(sink); |
| 229 // If inspected target is a render process Tracing.end will be handled by | 240 // If inspected target is a render process Tracing.end will be handled by |
| 230 // tracing agent in the renderer. | 241 // tracing agent in the renderer. |
| 231 return target_ == Renderer ? Response::FallThrough() : Response::OK(); | 242 if (target_ == Renderer) |
| 243 callback->fallThrough(); | |
| 244 else | |
| 245 callback->sendSuccess(); | |
| 232 } | 246 } |
| 233 | 247 |
| 234 Response TracingHandler::GetCategories(DevToolsCommandId command_id) { | 248 void TracingHandler::GetCategories( |
| 249 std::unique_ptr<GetCategoriesCallback> callback) { | |
| 235 TracingController::GetInstance()->GetCategories( | 250 TracingController::GetInstance()->GetCategories( |
| 236 base::Bind(&TracingHandler::OnCategoriesReceived, | 251 base::Bind(&TracingHandler::OnCategoriesReceived, |
| 237 weak_factory_.GetWeakPtr(), | 252 weak_factory_.GetWeakPtr(), |
| 238 command_id)); | 253 base::Passed(std::move(callback)))); |
| 239 return Response::OK(); | |
| 240 } | 254 } |
| 241 | 255 |
| 242 void TracingHandler::OnRecordingEnabled(DevToolsCommandId command_id) { | 256 void TracingHandler::OnRecordingEnabled( |
| 257 std::unique_ptr<StartCallback> callback) { | |
| 243 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 258 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), |
| 244 "TracingStartedInBrowser", TRACE_EVENT_SCOPE_THREAD, | 259 "TracingStartedInBrowser", TRACE_EVENT_SCOPE_THREAD, |
| 245 "frameTreeNodeId", frame_tree_node_id_); | 260 "frameTreeNodeId", frame_tree_node_id_); |
| 246 if (target_ != Renderer) | 261 if (target_ != Renderer) |
| 247 client_->SendStartResponse(command_id, StartResponse::Create()); | 262 callback->sendSuccess(); |
| 248 } | 263 } |
| 249 | 264 |
| 250 void TracingHandler::OnBufferUsage(float percent_full, | 265 void TracingHandler::OnBufferUsage(float percent_full, |
| 251 size_t approximate_event_count) { | 266 size_t approximate_event_count) { |
| 252 // TODO(crbug426117): remove set_value once all clients have switched to | 267 // TODO(crbug426117): remove set_value once all clients have switched to |
| 253 // the new interface of the event. | 268 // the new interface of the event. |
| 254 client_->BufferUsage(BufferUsageParams::Create() | 269 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 } | 270 } |
| 259 | 271 |
| 260 void TracingHandler::OnCategoriesReceived( | 272 void TracingHandler::OnCategoriesReceived( |
| 261 DevToolsCommandId command_id, | 273 std::unique_ptr<GetCategoriesCallback> callback, |
| 262 const std::set<std::string>& category_set) { | 274 const std::set<std::string>& category_set) { |
| 263 std::vector<std::string> categories; | 275 std::unique_ptr<protocol::Array<std::string>> categories = |
| 276 protocol::Array<std::string>::create(); | |
| 264 for (const std::string& category : category_set) | 277 for (const std::string& category : category_set) |
| 265 categories.push_back(category); | 278 categories->addItem(category); |
| 266 client_->SendGetCategoriesResponse(command_id, | 279 callback->sendSuccess(std::move(categories)); |
| 267 GetCategoriesResponse::Create()->set_categories(categories)); | |
| 268 } | 280 } |
| 269 | 281 |
| 270 Response TracingHandler::RequestMemoryDump(DevToolsCommandId command_id) { | 282 void TracingHandler::RequestMemoryDump( |
| 271 if (!IsTracing()) | 283 std::unique_ptr<RequestMemoryDumpCallback> callback) { |
| 272 return Response::InternalError("Tracing is not started"); | 284 if (!IsTracing()) { |
| 285 callback->sendFailure(Response::Error("Tracing is not started")); | |
| 286 return; | |
| 287 } | |
| 273 | 288 |
| 274 base::trace_event::MemoryDumpManager::GetInstance()->RequestGlobalDump( | 289 base::trace_event::MemoryDumpManager::GetInstance()->RequestGlobalDump( |
| 275 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED, | 290 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED, |
| 276 base::trace_event::MemoryDumpLevelOfDetail::DETAILED, | 291 base::trace_event::MemoryDumpLevelOfDetail::DETAILED, |
| 277 base::Bind(&TracingHandler::OnMemoryDumpFinished, | 292 base::Bind(&TracingHandler::OnMemoryDumpFinished, |
| 278 weak_factory_.GetWeakPtr(), command_id)); | 293 weak_factory_.GetWeakPtr(), |
| 279 return Response::OK(); | 294 base::Passed(std::move(callback)))); |
| 280 } | 295 } |
| 281 | 296 |
| 282 void TracingHandler::OnMemoryDumpFinished(DevToolsCommandId command_id, | 297 void TracingHandler::OnMemoryDumpFinished( |
| 283 uint64_t dump_guid, | 298 std::unique_ptr<RequestMemoryDumpCallback> callback, |
| 284 bool success) { | 299 uint64_t dump_guid, |
| 285 client_->SendRequestMemoryDumpResponse( | 300 bool success) { |
| 286 command_id, | 301 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 } | 302 } |
| 291 | 303 |
| 292 Response TracingHandler::RecordClockSyncMarker(const std::string& sync_id) { | 304 Response TracingHandler::RecordClockSyncMarker(const std::string& sync_id) { |
| 293 if (!IsTracing()) | 305 if (!IsTracing()) |
| 294 return Response::InternalError("Tracing is not started"); | 306 return Response::Error("Tracing is not started"); |
| 295 | 307 |
| 296 TracingControllerImpl::GetInstance()->RecordClockSyncMarker( | 308 TracingControllerImpl::GetInstance()->RecordClockSyncMarker( |
| 297 sync_id, | 309 sync_id, |
| 298 base::trace_event::TracingAgent::RecordClockSyncMarkerCallback()); | 310 base::trace_event::TracingAgent::RecordClockSyncMarkerCallback()); |
| 299 | 311 |
| 300 return Response::OK(); | 312 return Response::OK(); |
| 301 } | 313 } |
| 302 | 314 |
| 303 void TracingHandler::SetupTimer(double usage_reporting_interval) { | 315 void TracingHandler::SetupTimer(double usage_reporting_interval) { |
| 304 if (usage_reporting_interval == 0) return; | 316 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())); | 355 static_cast<base::DictionaryValue*>(value.release())); |
| 344 | 356 |
| 345 std::string mode; | 357 std::string mode; |
| 346 if (tracing_dict->GetString(kRecordModeParam, &mode)) | 358 if (tracing_dict->GetString(kRecordModeParam, &mode)) |
| 347 tracing_dict->SetString(kRecordModeParam, ConvertFromCamelCase(mode, '-')); | 359 tracing_dict->SetString(kRecordModeParam, ConvertFromCamelCase(mode, '-')); |
| 348 | 360 |
| 349 return base::trace_event::TraceConfig(*tracing_dict); | 361 return base::trace_event::TraceConfig(*tracing_dict); |
| 350 } | 362 } |
| 351 | 363 |
| 352 } // namespace tracing | 364 } // namespace tracing |
| 353 } // namespace devtools | 365 } // namespace protocol |
| 354 } // namespace content | |
| OLD | NEW |