1 // Copyright (c) 2013 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. 4 #include "content/browser/tracing/tracing_controller_impl.h" 5 6 #include "base/bind.h" 7 #include "base/debug/trace_event.h" 8 #include "base/files/file_util.h" 9 #include "base/json/string_escape.h" 10 #include "base/macros.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "content/browser/tracing/trace_message_filter.h" 13 #include "content/browser/tracing/tracing_ui.h" 14 #include "content/common/child_process_messages.h" 15 #include "content/public/browser/browser_message_filter.h" 16 #include "content/public/common/content_switches.h" 17 18 #if defined(OS_CHROMEOS) 19 #include "chromeos/dbus/dbus_thread_manager.h" 20 #include "chromeos/dbus/debug_daemon_client.h" 21 #endif 22 23 #if defined(OS_WIN) 24 #include "content/browser/tracing/etw_system_event_consumer_win.h" 25 #endif 26 27 using base::debug::TraceLog; 28 using base::debug::TraceOptions; 29 using base::debug::CategoryFilter; 30 31 namespace content { 32 33 namespace { 34 35 base::LazyInstance<TracingControllerImpl>::Leaky g_controller = 36 LAZY_INSTANCE_INITIALIZER; 37 38 class FileTraceDataSink : public TracingController::TraceDataSink { 39 public: 40 explicit FileTraceDataSink(const base::FilePath& trace_file_path, 41 const base::Closure& callback) 42 : file_path_(trace_file_path), 43 completion_callback_(callback), 44 file_(NULL) {} 45 46 virtual void AddTraceChunk(const std::string& chunk) OVERRIDE { 47 std::string tmp = chunk; 48 scoped_refptr<base::RefCountedString> chunk_ptr = 49 base::RefCountedString::TakeString(&tmp); 50 BrowserThread::PostTask( 51 BrowserThread::FILE, 52 FROM_HERE, 53 base::Bind( 54 &FileTraceDataSink::AddTraceChunkOnFileThread, this, chunk_ptr)); 55 } 56 virtual void SetSystemTrace(const std::string& data) OVERRIDE { 57 system_trace_ = data; 58 } 59 virtual void Close() OVERRIDE { 60 BrowserThread::PostTask( 61 BrowserThread::FILE, 62 FROM_HERE, 63 base::Bind(&FileTraceDataSink::CloseOnFileThread, this)); 64 } 65 66 private: 67 virtual ~FileTraceDataSink() { DCHECK(file_ == NULL); } 68 69 void AddTraceChunkOnFileThread( 70 const scoped_refptr<base::RefCountedString> chunk) { 71 if (file_ != NULL) 72 fputc(',', file_); 73 else if (!OpenFileIfNeededOnFileThread()) 74 return; 75 ignore_result(fwrite(chunk->data().c_str(), strlen(chunk->data().c_str()), 76 1, file_)); 77 } 78 79 bool OpenFileIfNeededOnFileThread() { 80 if (file_ != NULL) 81 return true; 82 file_ = base::OpenFile(file_path_, "w"); 83 if (file_ == NULL) { 84 LOG(ERROR) << "Failed to open " << file_path_.value(); 85 return false; 86 } 87 const char preamble[] = "{\"traceEvents\": ["; 88 ignore_result(fwrite(preamble, strlen(preamble), 1, file_)); 89 return true; 90 } 91 92 void CloseOnFileThread() { 93 if (OpenFileIfNeededOnFileThread()) { 94 fputc(']', file_); 95 if (!system_trace_.empty()) { 96 const char systemTraceEvents[] = ",\"systemTraceEvents\": "; 97 ignore_result(fwrite(systemTraceEvents, strlen(systemTraceEvents), 98 1, file_)); 99 ignore_result(fwrite(system_trace_.c_str(), 100 strlen(system_trace_.c_str()), 1, file_)); 101 } 102 fputc('}', file_); 103 base::CloseFile(file_); 104 file_ = NULL; 105 } 106 BrowserThread::PostTask( 107 BrowserThread::UI, 108 FROM_HERE, 109 base::Bind(&FileTraceDataSink::FinalizeOnUIThread, this)); 110 } 111 112 void FinalizeOnUIThread() { completion_callback_.Run(); } 113 114 base::FilePath file_path_; 115 base::Closure completion_callback_; 116 FILE* file_; 117 std::string system_trace_; 118 119 DISALLOW_COPY_AND_ASSIGN(FileTraceDataSink); 120 }; 121 122 class StringTraceDataSink : public TracingController::TraceDataSink { 123 public: 124 typedef base::Callback<void(base::RefCountedString*)> CompletionCallback; 125 126 explicit StringTraceDataSink(CompletionCallback callback) 127 : completion_callback_(callback) {} 128 129 // TracingController::TraceDataSink implementation 130 virtual void AddTraceChunk(const std::string& chunk) OVERRIDE { 131 if (!trace_.empty()) 132 trace_ += ","; 133 trace_ += chunk; 134 } 135 virtual void SetSystemTrace(const std::string& data) OVERRIDE { 136 system_trace_ = data; 137 } 138 virtual void Close() OVERRIDE { 139 std::string result = "{\"traceEvents\":[" + trace_ + "]"; 140 if (!system_trace_.empty()) 141 result += ",\"systemTraceEvents\": " + system_trace_; 142 result += "}"; 143 144 scoped_refptr<base::RefCountedString> str = 145 base::RefCountedString::TakeString(&result); 146 completion_callback_.Run(str.get()); 147 } 148 149 private: 150 virtual ~StringTraceDataSink() {} 151 152 std::string trace_; 153 std::string system_trace_; 154 CompletionCallback completion_callback_; 155 156 DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink); 157 }; 158 159 } // namespace 160 161 TracingController* TracingController::GetInstance() { 162 return TracingControllerImpl::GetInstance(); 163 } 164 165 TracingControllerImpl::TracingControllerImpl() : 166 pending_disable_recording_ack_count_(0), 167 pending_capture_monitoring_snapshot_ack_count_(0), 168 pending_trace_buffer_percent_full_ack_count_(0), 169 maximum_trace_buffer_percent_full_(0), 170 // Tracing may have been enabled by ContentMainRunner if kTraceStartup 171 // is specified in command line. 172 #if defined(OS_CHROMEOS) || defined(OS_WIN) 173 is_system_tracing_(false), 174 #endif 175 is_recording_(TraceLog::GetInstance()->IsEnabled()), 176 is_monitoring_(false) { 177 } 178 179 TracingControllerImpl::~TracingControllerImpl() { 180 // This is a Leaky instance. 181 NOTREACHED(); 182 } 183 184 TracingControllerImpl* TracingControllerImpl::GetInstance() { 185 return g_controller.Pointer(); 186 } 187 188 bool TracingControllerImpl::GetCategories( 189 const GetCategoriesDoneCallback& callback) { 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 191 192 // Known categories come back from child processes with the EndTracingAck 193 // message. So to get known categories, just begin and end tracing immediately 194 // afterwards. This will ping all the child processes for categories. 195 pending_get_categories_done_callback_ = callback; 196 if (!EnableRecording( 197 CategoryFilter("*"), TraceOptions(), EnableRecordingDoneCallback())) { 198 pending_get_categories_done_callback_.Reset(); 199 return false; 200 } 201 202 bool ok = DisableRecording(NULL); 203 DCHECK(ok); 204 return true; 205 } 206 207 void TracingControllerImpl::SetEnabledOnFileThread( 208 const CategoryFilter& category_filter, 209 int mode, 210 const TraceOptions& trace_options, 211 const base::Closure& callback) { 212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 213 214 TraceLog::GetInstance()->SetEnabled( 215 category_filter, static_cast<TraceLog::Mode>(mode), trace_options); 216 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); 217 } 218 219 void TracingControllerImpl::SetDisabledOnFileThread( 220 const base::Closure& callback) { 221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 222 223 TraceLog::GetInstance()->SetDisabled(); 224 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); 225 } 226 227 bool TracingControllerImpl::EnableRecording( 228 const CategoryFilter& category_filter, 229 const TraceOptions& trace_options, 230 const EnableRecordingDoneCallback& callback) { 231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 232 233 if (!can_enable_recording()) 234 return false; 235 is_recording_ = true; 236 237 #if defined(OS_ANDROID) 238 if (pending_get_categories_done_callback_.is_null()) 239 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); 240 #endif 241 242 trace_options_ = trace_options; 243 244 if (trace_options.enable_systrace) { 245 #if defined(OS_CHROMEOS) 246 DCHECK(!is_system_tracing_); 247 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> 248 StartSystemTracing(); 249 is_system_tracing_ = true; 250 #elif defined(OS_WIN) 251 DCHECK(!is_system_tracing_); 252 is_system_tracing_ = 253 EtwSystemEventConsumer::GetInstance()->StartSystemTracing(); 254 #endif 255 } 256 257 258 base::Closure on_enable_recording_done_callback = 259 base::Bind(&TracingControllerImpl::OnEnableRecordingDone, 260 base::Unretained(this), 261 category_filter, trace_options, callback); 262 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 263 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread, 264 base::Unretained(this), 265 category_filter, 266 base::debug::TraceLog::RECORDING_MODE, 267 trace_options, 268 on_enable_recording_done_callback)); 269 return true; 270 } 271 272 void TracingControllerImpl::OnEnableRecordingDone( 273 const CategoryFilter& category_filter, 274 const TraceOptions& trace_options, 275 const EnableRecordingDoneCallback& callback) { 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 277 278 // Notify all child processes. 279 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); 280 it != trace_message_filters_.end(); ++it) { 281 it->get()->SendBeginTracing(category_filter, trace_options); 282 } 283 284 if (!callback.is_null()) 285 callback.Run(); 286 } 287 288 bool TracingControllerImpl::DisableRecording( 289 const scoped_refptr<TraceDataSink>& trace_data_sink) { 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 291 292 if (!can_disable_recording()) 293 return false; 294 295 trace_data_sink_ = trace_data_sink; 296 trace_options_ = TraceOptions(); 297 // Disable local trace early to avoid traces during end-tracing process from 298 // interfering with the process. 299 base::Closure on_disable_recording_done_callback = base::Bind( 300 &TracingControllerImpl::OnDisableRecordingDone, base::Unretained(this)); 301 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 302 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread, 303 base::Unretained(this), 304 on_disable_recording_done_callback)); 305 return true; 306 } 307 308 void TracingControllerImpl::OnDisableRecordingDone() { 309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 310 311 #if defined(OS_ANDROID) 312 if (pending_get_categories_done_callback_.is_null()) 313 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); 314 #endif 315 316 // Count myself (local trace) in pending_disable_recording_ack_count_, 317 // acked below. 318 pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1; 319 pending_disable_recording_filters_ = trace_message_filters_; 320 321 #if defined(OS_CHROMEOS) || defined(OS_WIN) 322 if (is_system_tracing_) { 323 // Disable system tracing. 324 is_system_tracing_ = false; 325 ++pending_disable_recording_ack_count_; 326 327 #if defined(OS_CHROMEOS) 328 scoped_refptr<base::TaskRunner> task_runner = 329 BrowserThread::GetBlockingPool(); 330 chromeos::DBusThreadManager::Get() 331 ->GetDebugDaemonClient() 332 ->RequestStopSystemTracing( 333 task_runner, 334 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked, 335 base::Unretained(this))); 336 #elif defined(OS_WIN) 337 EtwSystemEventConsumer::GetInstance()->StopSystemTracing( 338 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked, 339 base::Unretained(this))); 340 #endif 341 } 342 #endif // defined(OS_CHROMEOS) || defined(OS_WIN) 343 344 // Handle special case of zero child processes by immediately flushing the 345 // trace log. Once the flush has completed the caller will be notified that 346 // tracing has ended. 347 if (pending_disable_recording_ack_count_ == 1) { 348 // Flush asynchronously now, because we don't have any children to wait for. 349 TraceLog::GetInstance()->Flush( 350 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected, 351 base::Unretained(this))); 352 } 353 354 // Notify all child processes. 355 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); 356 it != trace_message_filters_.end(); ++it) { 357 it->get()->SendEndTracing(); 358 } 359 } 360 361 bool TracingControllerImpl::EnableMonitoring( 362 const CategoryFilter& category_filter, 363 const TraceOptions& trace_options, 364 const EnableMonitoringDoneCallback& callback) { 365 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 366 367 if (!can_enable_monitoring()) 368 return false; 369 OnMonitoringStateChanged(true); 370 371 #if defined(OS_ANDROID) 372 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); 373 #endif 374 375 trace_options_ = trace_options; 376 377 base::Closure on_enable_monitoring_done_callback = 378 base::Bind(&TracingControllerImpl::OnEnableMonitoringDone, 379 base::Unretained(this), 380 category_filter, trace_options, callback); 381 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 382 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread, 383 base::Unretained(this), 384 category_filter, 385 base::debug::TraceLog::MONITORING_MODE, 386 trace_options, 387 on_enable_monitoring_done_callback)); 388 return true; 389 } 390 391 void TracingControllerImpl::OnEnableMonitoringDone( 392 const CategoryFilter& category_filter, 393 const TraceOptions& trace_options, 394 const EnableMonitoringDoneCallback& callback) { 395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 396 397 // Notify all child processes. 398 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); 399 it != trace_message_filters_.end(); ++it) { 400 it->get()->SendEnableMonitoring(category_filter, trace_options); 401 } 402 403 if (!callback.is_null()) 404 callback.Run(); 405 } 406 407 bool TracingControllerImpl::DisableMonitoring( 408 const DisableMonitoringDoneCallback& callback) { 409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 410 411 if (!can_disable_monitoring()) 412 return false; 413 414 trace_options_ = TraceOptions(); 415 base::Closure on_disable_monitoring_done_callback = 416 base::Bind(&TracingControllerImpl::OnDisableMonitoringDone, 417 base::Unretained(this), callback); 418 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 419 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread, 420 base::Unretained(this), 421 on_disable_monitoring_done_callback)); 422 return true; 423 } 424 425 scoped_refptr<TracingController::TraceDataSink> 426 TracingController::CreateStringSink( 427 const base::Callback<void(base::RefCountedString*)>& callback) { 428 return new StringTraceDataSink(callback); 429 } 430 431 scoped_refptr<TracingController::TraceDataSink> 432 TracingController::CreateFileSink(const base::FilePath& file_path, 433 const base::Closure& callback) { 434 return new FileTraceDataSink(file_path, callback); 435 } 436 437 void TracingControllerImpl::OnDisableMonitoringDone( 438 const DisableMonitoringDoneCallback& callback) { 439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 440 441 OnMonitoringStateChanged(false); 442 443 // Notify all child processes. 444 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); 445 it != trace_message_filters_.end(); ++it) { 446 it->get()->SendDisableMonitoring(); 447 } 448 if (!callback.is_null()) 449 callback.Run(); 450 } 451 452 void TracingControllerImpl::GetMonitoringStatus( 453 bool* out_enabled, 454 CategoryFilter* out_category_filter, 455 TraceOptions* out_trace_options) { 456 *out_enabled = is_monitoring_; 457 *out_category_filter = TraceLog::GetInstance()->GetCurrentCategoryFilter(); 458 *out_trace_options = trace_options_; 459 } 460 461 bool TracingControllerImpl::CaptureMonitoringSnapshot( 462 const scoped_refptr<TraceDataSink>& monitoring_data_sink) { 463 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 464 465 if (!can_disable_monitoring()) 466 return false; 467 468 if (!monitoring_data_sink.get()) 469 return false; 470 471 monitoring_data_sink_ = monitoring_data_sink; 472 473 // Count myself in pending_capture_monitoring_snapshot_ack_count_, 474 // acked below. 475 pending_capture_monitoring_snapshot_ack_count_ = 476 trace_message_filters_.size() + 1; 477 pending_capture_monitoring_filters_ = trace_message_filters_; 478 479 // Handle special case of zero child processes by immediately flushing the 480 // trace log. Once the flush has completed the caller will be notified that 481 // the capture snapshot has ended. 482 if (pending_capture_monitoring_snapshot_ack_count_ == 1) { 483 // Flush asynchronously now, because we don't have any children to wait for. 484 TraceLog::GetInstance()->FlushButLeaveBufferIntact( 485 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected, 486 base::Unretained(this))); 487 } 488 489 // Notify all child processes. 490 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); 491 it != trace_message_filters_.end(); ++it) { 492 it->get()->SendCaptureMonitoringSnapshot(); 493 } 494 495 #if defined(OS_ANDROID) 496 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); 497 #endif 498 499 return true; 500 } 501 502 bool TracingControllerImpl::GetTraceBufferPercentFull( 503 const GetTraceBufferPercentFullCallback& callback) { 504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 505 506 if (!can_get_trace_buffer_percent_full() || callback.is_null()) 507 return false; 508 509 pending_trace_buffer_percent_full_callback_ = callback; 510 511 // Count myself in pending_trace_buffer_percent_full_ack_count_, acked below. 512 pending_trace_buffer_percent_full_ack_count_ = 513 trace_message_filters_.size() + 1; 514 pending_trace_buffer_percent_full_filters_ = trace_message_filters_; 515 maximum_trace_buffer_percent_full_ = 0; 516 517 // Call OnTraceBufferPercentFullReply unconditionally for the browser process. 518 // This will result in immediate execution of the callback if there are no 519 // child processes. 520 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 521 base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply, 522 base::Unretained(this), 523 scoped_refptr<TraceMessageFilter>(), 524 TraceLog::GetInstance()->GetBufferPercentFull())); 525 526 // Notify all child processes. 527 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); 528 it != trace_message_filters_.end(); ++it) { 529 it->get()->SendGetTraceBufferPercentFull(); 530 } 531 return true; 532 } 533 534 bool TracingControllerImpl::SetWatchEvent( 535 const std::string& category_name, 536 const std::string& event_name, 537 const WatchEventCallback& callback) { 538 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 539 540 if (callback.is_null()) 541 return false; 542 543 watch_category_name_ = category_name; 544 watch_event_name_ = event_name; 545 watch_event_callback_ = callback; 546 547 TraceLog::GetInstance()->SetWatchEvent( 548 category_name, event_name, 549 base::Bind(&TracingControllerImpl::OnWatchEventMatched, 550 base::Unretained(this))); 551 552 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); 553 it != trace_message_filters_.end(); ++it) { 554 it->get()->SendSetWatchEvent(category_name, event_name); 555 } 556 return true; 557 } 558 559 bool TracingControllerImpl::CancelWatchEvent() { 560 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 561 562 if (!can_cancel_watch_event()) 563 return false; 564 565 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); 566 it != trace_message_filters_.end(); ++it) { 567 it->get()->SendCancelWatchEvent(); 568 } 569 570 watch_event_callback_.Reset(); 571 return true; 572 } 573 574 void TracingControllerImpl::AddTraceMessageFilter( 575 TraceMessageFilter* trace_message_filter) { 576 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 577 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 578 base::Bind(&TracingControllerImpl::AddTraceMessageFilter, 579 base::Unretained(this), 580 make_scoped_refptr(trace_message_filter))); 581 return; 582 } 583 584 trace_message_filters_.insert(trace_message_filter); 585 if (can_cancel_watch_event()) { 586 trace_message_filter->SendSetWatchEvent(watch_category_name_, 587 watch_event_name_); 588 } 589 if (can_disable_recording()) { 590 trace_message_filter->SendBeginTracing( 591 TraceLog::GetInstance()->GetCurrentCategoryFilter(), 592 TraceLog::GetInstance()->GetCurrentTraceOptions()); 593 } 594 if (can_disable_monitoring()) { 595 trace_message_filter->SendEnableMonitoring( 596 TraceLog::GetInstance()->GetCurrentCategoryFilter(), 597 TraceLog::GetInstance()->GetCurrentTraceOptions()); 598 } 599 } 600 601 void TracingControllerImpl::RemoveTraceMessageFilter( 602 TraceMessageFilter* trace_message_filter) { 603 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 604 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 605 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter, 606 base::Unretained(this), 607 make_scoped_refptr(trace_message_filter))); 608 return; 609 } 610 611 // If a filter is removed while a response from that filter is pending then 612 // simulate the response. Otherwise the response count will be wrong and the 613 // completion callback will never be executed. 614 if (pending_disable_recording_ack_count_ > 0) { 615 TraceMessageFilterSet::const_iterator it = 616 pending_disable_recording_filters_.find(trace_message_filter); 617 if (it != pending_disable_recording_filters_.end()) { 618 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 619 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked, 620 base::Unretained(this), 621 make_scoped_refptr(trace_message_filter), 622 std::vector<std::string>())); 623 } 624 } 625 if (pending_capture_monitoring_snapshot_ack_count_ > 0) { 626 TraceMessageFilterSet::const_iterator it = 627 pending_capture_monitoring_filters_.find(trace_message_filter); 628 if (it != pending_capture_monitoring_filters_.end()) { 629 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 630 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked, 631 base::Unretained(this), 632 make_scoped_refptr(trace_message_filter))); 633 } 634 } 635 if (pending_trace_buffer_percent_full_ack_count_ > 0) { 636 TraceMessageFilterSet::const_iterator it = 637 pending_trace_buffer_percent_full_filters_.find(trace_message_filter); 638 if (it != pending_trace_buffer_percent_full_filters_.end()) { 639 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 640 base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply, 641 base::Unretained(this), 642 make_scoped_refptr(trace_message_filter), 643 0)); 644 } 645 } 646 647 trace_message_filters_.erase(trace_message_filter); 648 } 649 650 void TracingControllerImpl::OnDisableRecordingAcked( 651 TraceMessageFilter* trace_message_filter, 652 const std::vector<std::string>& known_category_groups) { 653 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 654 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 655 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked, 656 base::Unretained(this), 657 make_scoped_refptr(trace_message_filter), 658 known_category_groups)); 659 return; 660 } 661 662 // Merge known_category_groups with known_category_groups_ 663 known_category_groups_.insert(known_category_groups.begin(), 664 known_category_groups.end()); 665 666 if (pending_disable_recording_ack_count_ == 0) 667 return; 668 669 if (trace_message_filter && 670 !pending_disable_recording_filters_.erase(trace_message_filter)) { 671 // The response from the specified message filter has already been received. 672 return; 673 } 674 675 if (--pending_disable_recording_ack_count_ == 1) { 676 // All acks from subprocesses have been received. Now flush the local trace. 677 // During or after this call, our OnLocalTraceDataCollected will be 678 // called with the last of the local trace data. 679 TraceLog::GetInstance()->Flush( 680 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected, 681 base::Unretained(this))); 682 return; 683 } 684 685 if (pending_disable_recording_ack_count_ != 0) 686 return; 687 688 // All acks (including from the subprocesses and the local trace) have been 689 // received. 690 is_recording_ = false; 691 692 // Trigger callback if one is set. 693 if (!pending_get_categories_done_callback_.is_null()) { 694 pending_get_categories_done_callback_.Run(known_category_groups_); 695 pending_get_categories_done_callback_.Reset(); 696 } else if (trace_data_sink_.get()) { 697 trace_data_sink_->Close(); 698 trace_data_sink_ = NULL; 699 } 700 } 701 702 #if defined(OS_CHROMEOS) || defined(OS_WIN) 703 void TracingControllerImpl::OnEndSystemTracingAcked( 704 const scoped_refptr<base::RefCountedString>& events_str_ptr) { 705 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 706 707 if (trace_data_sink_.get()) { 708 #if defined(OS_WIN) 709 // The Windows kernel events are kept into a JSon format stored as string 710 // and must not be escaped. 711 std::string json_string = events_str_ptr->data(); 712 #else 713 std::string json_string = 714 base::GetQuotedJSONString(events_str_ptr->data()); 715 #endif 716 trace_data_sink_->SetSystemTrace(json_string); 717 } 718 DCHECK(!is_system_tracing_); 719 std::vector<std::string> category_groups; 720 OnDisableRecordingAcked(NULL, category_groups); 721 } 722 #endif 723 724 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked( 725 TraceMessageFilter* trace_message_filter) { 726 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 727 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 728 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked, 729 base::Unretained(this), 730 make_scoped_refptr(trace_message_filter))); 731 return; 732 } 733 734 if (pending_capture_monitoring_snapshot_ack_count_ == 0) 735 return; 736 737 if (trace_message_filter && 738 !pending_capture_monitoring_filters_.erase(trace_message_filter)) { 739 // The response from the specified message filter has already been received. 740 return; 741 } 742 743 if (--pending_capture_monitoring_snapshot_ack_count_ == 1) { 744 // All acks from subprocesses have been received. Now flush the local trace. 745 // During or after this call, our OnLocalMonitoringTraceDataCollected 746 // will be called with the last of the local trace data. 747 TraceLog::GetInstance()->FlushButLeaveBufferIntact( 748 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected, 749 base::Unretained(this))); 750 return; 751 } 752 753 if (pending_capture_monitoring_snapshot_ack_count_ != 0) 754 return; 755 756 if (monitoring_data_sink_.get()) { 757 monitoring_data_sink_->Close(); 758 monitoring_data_sink_ = NULL; 759 } 760 } 761 762 void TracingControllerImpl::OnTraceDataCollected( 763 const scoped_refptr<base::RefCountedString>& events_str_ptr) { 764 // OnTraceDataCollected may be called from any browser thread, either by the 765 // local event trace system or from child processes via TraceMessageFilter. 766 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 767 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 768 base::Bind(&TracingControllerImpl::OnTraceDataCollected, 769 base::Unretained(this), events_str_ptr)); 770 return; 771 } 772 773 if (trace_data_sink_.get()) 774 trace_data_sink_->AddTraceChunk(events_str_ptr->data()); 775 } 776 777 void TracingControllerImpl::OnMonitoringTraceDataCollected( 778 const scoped_refptr<base::RefCountedString>& events_str_ptr) { 779 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 780 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 781 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected, 782 base::Unretained(this), events_str_ptr)); 783 return; 784 } 785 786 if (monitoring_data_sink_.get()) 787 monitoring_data_sink_->AddTraceChunk(events_str_ptr->data()); 788 } 789 790 void TracingControllerImpl::OnLocalTraceDataCollected( 791 const scoped_refptr<base::RefCountedString>& events_str_ptr, 792 bool has_more_events) { 793 if (events_str_ptr->data().size()) 794 OnTraceDataCollected(events_str_ptr); 795 796 if (has_more_events) 797 return; 798 799 // Simulate an DisableRecordingAcked for the local trace. 800 std::vector<std::string> category_groups; 801 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups); 802 OnDisableRecordingAcked(NULL, category_groups); 803 } 804 805 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected( 806 const scoped_refptr<base::RefCountedString>& events_str_ptr, 807 bool has_more_events) { 808 if (events_str_ptr->data().size()) 809 OnMonitoringTraceDataCollected(events_str_ptr); 810 811 if (has_more_events) 812 return; 813 814 // Simulate an CaptureMonitoringSnapshotAcked for the local trace. 815 OnCaptureMonitoringSnapshotAcked(NULL); 816 } 817 818 void TracingControllerImpl::OnTraceBufferPercentFullReply( 819 TraceMessageFilter* trace_message_filter, 820 float percent_full) { 821 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 822 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 823 base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply, 824 base::Unretained(this), 825 make_scoped_refptr(trace_message_filter), 826 percent_full)); 827 return; 828 } 829 830 if (pending_trace_buffer_percent_full_ack_count_ == 0) 831 return; 832 833 if (trace_message_filter && 834 !pending_trace_buffer_percent_full_filters_.erase(trace_message_filter)) { 835 // The response from the specified message filter has already been received. 836 return; 837 } 838 839 maximum_trace_buffer_percent_full_ = 840 std::max(maximum_trace_buffer_percent_full_, percent_full); 841 842 if (--pending_trace_buffer_percent_full_ack_count_ == 0) { 843 // Trigger callback if one is set. 844 pending_trace_buffer_percent_full_callback_.Run( 845 maximum_trace_buffer_percent_full_); 846 pending_trace_buffer_percent_full_callback_.Reset(); 847 } 848 } 849 850 void TracingControllerImpl::OnWatchEventMatched() { 851 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 852 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 853 base::Bind(&TracingControllerImpl::OnWatchEventMatched, 854 base::Unretained(this))); 855 return; 856 } 857 858 if (!watch_event_callback_.is_null()) 859 watch_event_callback_.Run(); 860 } 861 862 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) { 863 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end()); 864 tracing_uis_.insert(tracing_ui); 865 } 866 867 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) { 868 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui); 869 DCHECK(it != tracing_uis_.end()); 870 tracing_uis_.erase(it); 871 } 872 873 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) { 874 if (is_monitoring_ == is_monitoring) 875 return; 876 877 is_monitoring_ = is_monitoring; 878 #if !defined(OS_ANDROID) 879 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin(); 880 it != tracing_uis_.end(); it++) { 881 (*it)->OnMonitoringStateChanged(is_monitoring); 882 } 883 #endif 884 } 885 886 } // namespace content 887