| 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 |