Chromium Code Reviews| Index: content/browser/tracing/tracing_controller_impl.cc |
| diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc |
| index 8907550ab7ef5e5c63423945158a67566e197576..29ecd7866c7ec5d9d01215175492a089c8e5c2f4 100644 |
| --- a/content/browser/tracing/tracing_controller_impl.cc |
| +++ b/content/browser/tracing/tracing_controller_impl.cc |
| @@ -5,10 +5,9 @@ |
| #include "content/browser/tracing/tracing_controller_impl.h" |
| #include "base/bind.h" |
| +#include "base/debug/trace_event.h" |
| #include "base/file_util.h" |
| -#include "base/json/string_escape.h" |
| -#include "base/strings/string_number_conversions.h" |
| -#include "base/threading/thread_restrictions.h" |
| +#include "base/values.h" |
| #include "content/browser/tracing/trace_message_filter.h" |
| #include "content/common/child_process_messages.h" |
| #include "content/public/browser/browser_message_filter.h" |
| @@ -23,6 +22,13 @@ namespace { |
| base::LazyInstance<TracingControllerImpl>::Leaky g_controller = |
| LAZY_INSTANCE_INITIALIZER; |
| +// The keys of tracing parameters in JSON. Must keep consistent with |
| +// third_party/trace-viewer/src/about_tracing/begin_recording.js. |
| +const char kCategoryFilter[] = "categoryFilter"; |
| +const char kUseSystemTracing[] = "useSystemTracing"; |
| +const char kUseContinuousTracing[] = "useContinuousTracing"; |
| +const char kUseSampling[] = "useSampling"; |
| + |
| } // namespace |
| TracingController* TracingController::GetInstance() { |
| @@ -118,9 +124,7 @@ TracingControllerImpl::TracingControllerImpl() : |
| // Tracing may have been enabled by ContentMainRunner if kTraceStartup |
| // is specified in command line. |
| is_recording_(TraceLog::GetInstance()->IsEnabled()), |
| - is_monitoring_(false), |
| - category_filter_( |
| - base::debug::CategoryFilter::kDefaultCategoryFilterString) { |
| + is_monitoring_(false) { |
| } |
| TracingControllerImpl::~TracingControllerImpl() { |
| @@ -140,14 +144,13 @@ void TracingControllerImpl::GetCategories( |
| // message. So to get known categories, just begin and end tracing immediately |
| // afterwards. This will ping all the child processes for categories. |
| pending_get_categories_done_callback_ = callback; |
| - EnableRecording(base::debug::CategoryFilter("*"), |
| - TracingController::Options(), |
| + EnableRecording("*", TracingController::Options(), |
| EnableRecordingDoneCallback()); |
| DisableRecording(base::FilePath(), TracingFileResultCallback()); |
| } |
| bool TracingControllerImpl::EnableRecording( |
| - const base::debug::CategoryFilter& filter, |
| + const std::string& category_filter, |
| TracingController::Options options, |
| const EnableRecordingDoneCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| @@ -168,13 +171,14 @@ bool TracingControllerImpl::EnableRecording( |
| } |
| // TODO(haraken): How to handle ENABLE_SYSTRACE? |
| - TraceLog::GetInstance()->SetEnabled(filter, trace_options); |
| + TraceLog::GetInstance()->SetEnabled( |
| + base::debug::CategoryFilter(category_filter), trace_options); |
| is_recording_ = true; |
| - category_filter_ = TraceLog::GetInstance()->GetCurrentCategoryFilter(); |
| // Notify all child processes. |
| - for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { |
| - it->get()->SendBeginTracing(category_filter_.ToString(), trace_options); |
| + for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin(); |
| + it != trace_message_filters_.end(); ++it) { |
| + it->get()->SendBeginTracing(category_filter, trace_options); |
| } |
| if (!callback.is_null()) |
| @@ -204,15 +208,13 @@ bool TracingControllerImpl::DisableRecording( |
| if (!callback.is_null() || !result_file_path.empty()) |
| result_file_.reset(new ResultFile(result_file_path)); |
| - // 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_disable_recording_ack_count_, |
| // acked below. |
| - pending_disable_recording_ack_count_ = filters_.size() + 1; |
| + pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1; |
| - // Handle special case of zero child processes. |
| + // Handle special case of zero child processes by immediately telling the |
| + // caller that tracing has ended. Use asynchronous OnDisableRecordingAcked |
| + // to avoid recursive call back to the caller. |
| 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; |
| @@ -223,14 +225,15 @@ bool TracingControllerImpl::DisableRecording( |
| } |
| // Notify all child processes. |
| - for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { |
| + for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin(); |
| + it != trace_message_filters_.end(); ++it) { |
| it->get()->SendEndTracing(); |
| } |
| return true; |
| } |
| bool TracingControllerImpl::EnableMonitoring( |
| - const base::debug::CategoryFilter& filter, |
| + const std::string& category_filter, |
| TracingController::Options options, |
| const EnableMonitoringDoneCallback& callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| @@ -248,8 +251,9 @@ bool TracingControllerImpl::EnableMonitoring( |
| 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(), |
| + for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin(); |
| + it != trace_message_filters_.end(); ++it) { |
| + it->get()->SendEnableMonitoring(category_filter, |
| base::debug::TraceLog::Options(monitoring_tracing_options)); |
| } |
| @@ -267,7 +271,8 @@ bool TracingControllerImpl::DisableMonitoring( |
| is_monitoring_ = false; |
| // Notify all child processes. |
| - for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { |
| + for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin(); |
| + it != trace_message_filters_.end(); ++it) { |
| it->get()->SendDisableMonitoring(); |
| } |
| @@ -278,7 +283,7 @@ bool TracingControllerImpl::DisableMonitoring( |
| void TracingControllerImpl::GetMonitoringStatus( |
| bool* out_enabled, |
| - base::debug::CategoryFilter* out_filter, |
| + std::string* out_category_filter, |
| TracingController::Options* out_options) { |
| NOTIMPLEMENTED(); |
| } |
| @@ -296,15 +301,15 @@ void TracingControllerImpl::CaptureMonitoringSnapshot( |
| if (!callback.is_null() || !result_file_path.empty()) |
| monitoring_snapshot_file_.reset(new ResultFile(result_file_path)); |
| - // 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; |
| + pending_capture_monitoring_snapshot_ack_count_ = |
| + trace_message_filters_.size() + 1; |
| - // Handle special case of zero child processes. |
| + // Handle special case of zero child processes by immediately telling the |
| + // caller that capturing snapshot has ended. Use asynchronous |
| + // OnCaptureMonitoringSnapshotAcked to avoid recursive call back to the |
| + // caller. |
| 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, |
| @@ -313,7 +318,8 @@ void TracingControllerImpl::CaptureMonitoringSnapshot( |
| } |
| // Notify all child processes. |
| - for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { |
| + for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin(); |
| + it != trace_message_filters_.end(); ++it) { |
| it->get()->SendCaptureMonitoringSnapshot(); |
| } |
| @@ -332,7 +338,8 @@ bool TracingControllerImpl::GetTraceBufferPercentFull( |
| pending_trace_buffer_percent_full_callback_ = callback; |
| // Count myself in pending_trace_buffer_percent_full_ack_count_, acked below. |
| - pending_trace_buffer_percent_full_ack_count_ = filters_.size() + 1; |
| + pending_trace_buffer_percent_full_ack_count_ = |
| + trace_message_filters_.size() + 1; |
| // Handle special case of zero child processes. |
| if (pending_trace_buffer_percent_full_ack_count_ == 1) { |
| @@ -343,36 +350,75 @@ bool TracingControllerImpl::GetTraceBufferPercentFull( |
| } |
| // Notify all child processes. |
| - for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { |
| + for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin(); |
| + it != trace_message_filters_.end(); ++it) { |
| it->get()->SendGetTraceBufferPercentFull(); |
| } |
| return true; |
| } |
| -void TracingControllerImpl::AddFilter(TraceMessageFilter* filter) { |
| +bool TracingControllerImpl::SetWatchEvent( |
| + const std::string& category_name, |
| + const std::string& event_name, |
| + const WatchEventCallback& callback) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + if (!can_set_watch_event() || callback.is_null()) |
| + return false; |
| + |
| + watch_event_callback_ = callback; |
| + |
| + for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin(); |
| + it != trace_message_filters_.end(); ++it) { |
| + it->get()->SendSetWatchEvent(category_name, event_name); |
| + } |
| + return true; |
| +} |
| + |
| +bool TracingControllerImpl::CancelWatchEvent() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + if (!can_cancel_watch_event()) |
| + return false; |
| + |
| + for (TraceMessageFilterMap::iterator it = trace_message_filters_.begin(); |
| + it != trace_message_filters_.end(); ++it) { |
| + it->get()->SendCancelWatchEvent(); |
| + } |
| + |
| + watch_event_callback_.Reset(); |
| + return true; |
| +} |
| + |
| +void TracingControllerImpl::AddTraceMessageFilter( |
| + TraceMessageFilter* trace_message_filter) { |
| if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| - base::Bind(&TracingControllerImpl::AddFilter, base::Unretained(this), |
| - make_scoped_refptr(filter))); |
| + base::Bind(&TracingControllerImpl::AddTraceMessageFilter, |
| + base::Unretained(this), |
| + make_scoped_refptr(trace_message_filter))); |
| return; |
| } |
| - filters_.insert(filter); |
| + trace_message_filters_.insert(trace_message_filter); |
| if (can_disable_recording()) { |
| - std::string cf_str = category_filter_.ToString(); |
| - filter->SendBeginTracing(cf_str, TraceLog::GetInstance()->trace_options()); |
| + trace_message_filter->SendBeginTracing( |
| + TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString(), |
| + TraceLog::GetInstance()->trace_options()); |
| } |
| } |
| -void TracingControllerImpl::RemoveFilter(TraceMessageFilter* filter) { |
| +void TracingControllerImpl::RemoveTraceMessageFilter( |
| + TraceMessageFilter* trace_message_filter) { |
| if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| - base::Bind(&TracingControllerImpl::RemoveFilter, base::Unretained(this), |
| - make_scoped_refptr(filter))); |
| + base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter, |
| + base::Unretained(this), |
| + make_scoped_refptr(trace_message_filter))); |
| return; |
| } |
| - filters_.erase(filter); |
| + trace_message_filters_.erase(trace_message_filter); |
| } |
| void TracingControllerImpl::OnDisableRecordingAcked( |
| @@ -562,4 +608,55 @@ void TracingControllerImpl::OnTraceBufferPercentFullReply(float percent_full) { |
| } |
| } |
| +void TracingControllerImpl::OnWatchEventMatched() { |
| + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&TracingControllerImpl::OnWatchEventMatched, |
| + base::Unretained(this))); |
|
piman
2013/11/15 23:42:52
What makes Unretained here safe?
Xianzhu
2013/11/16 01:16:14
TracingControllerImpl instance is a leaky singleto
|
| + } |
| + |
| + if (!watch_event_callback_.is_null()) |
| + watch_event_callback_.Run(); |
| +} |
| + |
| +// static |
| +bool TracingControllerImpl::ParseTracingParams( |
| + const base::DictionaryValue* params, |
| + std::string* category_filter, |
| + Options* options) { |
| + bool use_system_tracing; |
| + bool use_continuous_tracing; |
| + bool use_sampling; |
| + |
| + if (!params->GetString(kCategoryFilter, category_filter) || |
| + !params->GetBoolean(kUseSystemTracing, &use_system_tracing) || |
| + !params->GetBoolean(kUseContinuousTracing, &use_continuous_tracing) || |
| + !params->GetBoolean(kUseSampling, &use_sampling)) { |
| + LOG(ERROR) << "Malformed params"; |
| + return false; |
| + } |
| + |
| + int tracing_options = 0; |
| + if (use_system_tracing) |
| + tracing_options |= ENABLE_SYSTRACE; |
| + if (use_continuous_tracing) |
| + tracing_options |= RECORD_CONTINUOUSLY; |
| + if (use_sampling) |
| + tracing_options |= ENABLE_SAMPLING; |
| + |
| + *options = static_cast<Options>(tracing_options); |
| + return true; |
| +} |
| + |
| +// static |
| +void TracingControllerImpl::EncodeTracingParams( |
| + const std::string& category_filter, |
| + Options options, |
| + base::DictionaryValue* result) { |
| + result->SetString(kCategoryFilter, category_filter); |
| + result->SetBoolean(kUseSystemTracing, options & ENABLE_SYSTRACE); |
| + result->SetBoolean(kUseContinuousTracing, options & RECORD_CONTINUOUSLY); |
| + result->SetBoolean(kUseSampling, options & ENABLE_SAMPLING); |
| +} |
| + |
| } // namespace content |