diff options
Diffstat (limited to 'content/browser/tracing/tracing_controller_impl.cc')
-rw-r--r-- | content/browser/tracing/tracing_controller_impl.cc | 194 |
1 files changed, 156 insertions, 38 deletions
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 1c1c43a..845f1c5 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc @@ -29,10 +29,14 @@ TracingController* TracingController::GetInstance() { } TracingControllerImpl::TracingControllerImpl() : - pending_end_ack_count_(0), + pending_disable_recording_ack_count_(0), + pending_capture_monitoring_snapshot_ack_count_(0), is_recording_(false), + is_monitoring_(false), category_filter_( - base::debug::CategoryFilter::kDefaultCategoryFilterString) { + base::debug::CategoryFilter::kDefaultCategoryFilterString), + result_file_(0), + result_file_has_at_least_one_result_(false) { } TracingControllerImpl::~TracingControllerImpl() { @@ -58,14 +62,14 @@ void TracingControllerImpl::GetCategories( DisableRecording(TracingFileResultCallback()); } -void TracingControllerImpl::EnableRecording( +bool TracingControllerImpl::EnableRecording( const base::debug::CategoryFilter& filter, TracingController::Options options, const EnableRecordingDoneCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (!can_enable_recording()) - return; + return false; trace_options_ = TraceLog::GetInstance()->trace_options(); TraceLog::GetInstance()->SetEnabled(filter, trace_options_); @@ -80,14 +84,15 @@ void TracingControllerImpl::EnableRecording( if (!callback.is_null()) callback.Run(); + return true; } -void TracingControllerImpl::DisableRecording( +bool TracingControllerImpl::DisableRecording( const TracingFileResultCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (!can_end_recording()) - return; + if (!can_disable_recording()) + return false; pending_disable_recording_done_callback_ = callback; @@ -99,18 +104,23 @@ void TracingControllerImpl::DisableRecording( if (pending_get_categories_done_callback_.is_null()) { base::FilePath temporary_file; file_util::CreateTemporaryFile(&temporary_file); - recording_result_file_.reset(new base::FilePath(temporary_file)); + result_file_path_.reset(new base::FilePath(temporary_file)); + result_file_ = file_util::OpenFile(*result_file_path_, "w"); + result_file_has_at_least_one_result_ = false; + const char* preamble = "{\"traceEvents\": ["; + fwrite(preamble, strlen(preamble), 1, result_file_); } // There could be a case where there are no child processes and filters_ // is empty. In that case we can immediately tell the subscriber that tracing // has ended. To avoid recursive calls back to the subscriber, we will just // use the existing asynchronous OnDisableRecordingAcked code. - // Count myself (local trace) in pending_end_ack_count_, acked below. - pending_end_ack_count_ = filters_.size() + 1; + // Count myself (local trace) in pending_disable_recording_ack_count_, + // acked below. + pending_disable_recording_ack_count_ = filters_.size() + 1; // Handle special case of zero child processes. - if (pending_end_ack_count_ == 1) { + if (pending_disable_recording_ack_count_ == 1) { // Ack asynchronously now, because we don't have any children to wait for. std::vector<std::string> category_groups; TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups); @@ -123,18 +133,50 @@ void TracingControllerImpl::DisableRecording( for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { it->get()->SendEndTracing(); } + return true; } -void TracingControllerImpl::EnableMonitoring( +bool TracingControllerImpl::EnableMonitoring( const base::debug::CategoryFilter& filter, TracingController::Options options, const EnableMonitoringDoneCallback& callback) { - NOTIMPLEMENTED(); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (!can_enable_monitoring()) + return false; + is_monitoring_ = true; + + int monitoring_tracing_options = 0; + if (options & ENABLE_SAMPLING) + monitoring_tracing_options |= base::debug::TraceLog::MONITOR_SAMPLING; + + // Notify all child processes. + for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { + it->get()->SendEnableMonitoring(filter.ToString(), + base::debug::TraceLog::Options(monitoring_tracing_options)); + } + + if (!callback.is_null()) + callback.Run(); + return true; } -void TracingControllerImpl::DisableMonitoring( +bool TracingControllerImpl::DisableMonitoring( const DisableMonitoringDoneCallback& callback) { - NOTIMPLEMENTED(); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (!can_disable_monitoring()) + return false; + is_monitoring_ = false; + + // Notify all child processes. + for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { + it->get()->SendDisableMonitoring(); + } + + if (!callback.is_null()) + callback.Run(); + return true; } void TracingControllerImpl::GetMonitoringStatus( @@ -144,9 +186,43 @@ void TracingControllerImpl::GetMonitoringStatus( NOTIMPLEMENTED(); } -void TracingControllerImpl::CaptureCurrentMonitoringSnapshot( +void TracingControllerImpl::CaptureMonitoringSnapshot( const TracingFileResultCallback& callback) { - NOTIMPLEMENTED(); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (!can_disable_monitoring()) + return; + + pending_capture_monitoring_snapshot_done_callback_ = callback; + + base::FilePath temporary_file; + file_util::CreateTemporaryFile(&temporary_file); + result_file_path_.reset(new base::FilePath(temporary_file)); + result_file_ = file_util::OpenFile(*result_file_path_, "w"); + result_file_has_at_least_one_result_ = false; + const char* preamble = "{\"traceEvents\": ["; + fwrite(preamble, strlen(preamble), 1, result_file_); + + // There could be a case where there are no child processes and filters_ + // is empty. In that case we can immediately tell the subscriber that tracing + // has ended. To avoid recursive calls back to the subscriber, we will just + // use the existing asynchronous OnCaptureMonitoringSnapshotAcked code. + // Count myself in pending_capture_monitoring_snapshot_ack_count_, + // acked below. + pending_capture_monitoring_snapshot_ack_count_ = filters_.size() + 1; + + // Handle special case of zero child processes. + if (pending_capture_monitoring_snapshot_ack_count_ == 1) { + // Ack asynchronously now, because we don't have any children to wait for. + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked, + base::Unretained(this))); + } + + // Notify all child processes. + for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { + it->get()->SendCaptureMonitoringSnapshot(); + } } void TracingControllerImpl::AddFilter(TraceMessageFilter* filter) { @@ -158,7 +234,7 @@ void TracingControllerImpl::AddFilter(TraceMessageFilter* filter) { } filters_.insert(filter); - if (is_recording_enabled()) { + if (can_disable_recording()) { std::string cf_str = category_filter_.ToString(); filter->SendBeginTracing(cf_str, trace_options_); } @@ -188,10 +264,10 @@ void TracingControllerImpl::OnDisableRecordingAcked( known_category_groups_.insert(known_category_groups.begin(), known_category_groups.end()); - if (pending_end_ack_count_ == 0) + if (pending_disable_recording_ack_count_ == 0) return; - if (--pending_end_ack_count_ == 1) { + if (--pending_disable_recording_ack_count_ == 1) { // All acks from subprocesses have been received. Now flush the local trace. // During or after this call, our OnLocalTraceDataCollected will be // called with the last of the local trace data. @@ -200,7 +276,7 @@ void TracingControllerImpl::OnDisableRecordingAcked( base::Unretained(this))); } - if (pending_end_ack_count_ != 0) + if (pending_disable_recording_ack_count_ != 0) return; // All acks (including from the subprocesses and the local trace) have been @@ -211,17 +287,48 @@ void TracingControllerImpl::OnDisableRecordingAcked( if (!pending_get_categories_done_callback_.is_null()) { pending_get_categories_done_callback_.Run(known_category_groups_); pending_get_categories_done_callback_.Reset(); - } else { - OnEndTracingComplete(); + } else if (!pending_disable_recording_done_callback_.is_null()) { + const char* trailout = "]}"; + fwrite(trailout, strlen(trailout), 1, result_file_); + file_util::CloseFile(result_file_); + result_file_ = 0; + pending_disable_recording_done_callback_.Run(result_file_path_.Pass()); + pending_disable_recording_done_callback_.Reset(); } } -void TracingControllerImpl::OnEndTracingComplete() { - if (pending_disable_recording_done_callback_.is_null()) +void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked() { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked, + base::Unretained(this))); + return; + } + + if (pending_capture_monitoring_snapshot_ack_count_ == 0) return; - pending_disable_recording_done_callback_.Run(recording_result_file_.Pass()); - pending_disable_recording_done_callback_.Reset(); + if (--pending_capture_monitoring_snapshot_ack_count_ == 1) { + // All acks from subprocesses have been received. Now flush the local trace. + // During or after this call, our OnLocalMonitoringTraceDataCollected + // will be called with the last of the local trace data. + TraceLog::GetInstance()->FlushButLeaveBufferIntact( + base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected, + base::Unretained(this))); + } + + if (pending_capture_monitoring_snapshot_ack_count_ != 0) + return; + + if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) { + const char* trailout = "]}"; + fwrite(trailout, strlen(trailout), 1, result_file_); + file_util::CloseFile(result_file_); + result_file_ = 0; + pending_capture_monitoring_snapshot_done_callback_.Run( + result_file_path_.Pass()); + pending_capture_monitoring_snapshot_done_callback_.Reset(); + } } void TracingControllerImpl::OnTraceDataCollected( @@ -239,17 +346,15 @@ void TracingControllerImpl::OnTraceDataCollected( if (!pending_get_categories_done_callback_.is_null()) return; - std::string javascript; - javascript.reserve(events_str_ptr->size() * 2); - base::JsonDoubleQuote(events_str_ptr->data(), false, &javascript); - - // Intentionally append a , to the traceData. This technically causes all - // traceData that we pass back to JS to end with a comma, but that is - // actually something the JS side strips away anyway - javascript.append(","); - - file_util::WriteFile(*recording_result_file_, - javascript.c_str(), javascript.length()); + // If there is already a result in the file, then put a commma + // before the next batch of results. + if (result_file_has_at_least_one_result_) { + fwrite(",", 1, 1, result_file_); + } else { + result_file_has_at_least_one_result_ = true; + } + fwrite(events_str_ptr->data().c_str(), events_str_ptr->data().size(), 1, + result_file_); } void TracingControllerImpl::OnLocalTraceDataCollected( @@ -267,4 +372,17 @@ void TracingControllerImpl::OnLocalTraceDataCollected( OnDisableRecordingAcked(category_groups); } +void TracingControllerImpl::OnLocalMonitoringTraceDataCollected( + const scoped_refptr<base::RefCountedString>& events_str_ptr, + bool has_more_events) { + if (events_str_ptr->data().size()) + OnTraceDataCollected(events_str_ptr); + + if (has_more_events) + return; + + // Simulate an CaptureMonitoringSnapshotAcked for the local trace. + OnCaptureMonitoringSnapshotAcked(); +} + } // namespace content |