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 |