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