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 d17c1226d839ad347a476c91ecd8fce0b401de9b..9ed3c03f2597aa037d38a71245e39060b16cc31e 100644 |
--- a/content/browser/tracing/tracing_controller_impl.cc |
+++ b/content/browser/tracing/tracing_controller_impl.cc |
@@ -10,6 +10,8 @@ |
#include "base/macros.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/sys_info.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "base/time/time.h" |
#include "base/trace_event/trace_event.h" |
#include "build/build_config.h" |
#include "components/tracing/process_metrics_memory_dump_provider.h" |
@@ -51,7 +53,9 @@ const char kChromeTracingAgentName[] = "chrome"; |
const char kETWTracingAgentName[] = "etw"; |
const char kChromeTraceLabel[] = "traceEvents"; |
+const int kStartTracingTimeoutSeconds = 30; |
const int kIssueClockSyncTimeoutSeconds = 30; |
+const int kStopTracingRetryTimeMilliseconds = 100; |
std::string GetNetworkTypeString() { |
switch (net::NetworkChangeNotifier::GetConnectionType()) { |
@@ -145,7 +149,8 @@ TracingController* TracingController::GetInstance() { |
} |
TracingControllerImpl::TracingControllerImpl() |
- : pending_stop_tracing_ack_count_(0), |
+ : pending_start_tracing_ack_count_(0), |
+ pending_stop_tracing_ack_count_(0), |
pending_capture_monitoring_snapshot_ack_count_(0), |
pending_trace_log_status_ack_count_(0), |
maximum_trace_buffer_usage_(0), |
@@ -219,6 +224,9 @@ bool TracingControllerImpl::StartTracing( |
return false; |
is_tracing_ = true; |
start_tracing_done_callback_ = callback; |
+ start_tracing_trace_config_.reset( |
+ new base::trace_event::TraceConfig(trace_config)); |
+ pending_start_tracing_ack_count_ = 0; |
#if defined(OS_ANDROID) |
if (pending_get_categories_done_callback_.is_null()) |
@@ -226,57 +234,88 @@ bool TracingControllerImpl::StartTracing( |
#endif |
if (trace_config.IsSystraceEnabled()) { |
- if (PowerTracingAgent::GetInstance()->StartAgentTracing(trace_config)) |
- additional_tracing_agents_.push_back(PowerTracingAgent::GetInstance()); |
+ PowerTracingAgent::GetInstance()->StartAgentTracing( |
+ trace_config, |
+ base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked, |
+ base::Unretained(this))); |
+ ++pending_start_tracing_ack_count_; |
+ |
#if defined(OS_CHROMEOS) |
chromeos::DebugDaemonClient* debug_daemon = |
chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); |
- if (debug_daemon && debug_daemon->StartAgentTracing(trace_config)) { |
- debug_daemon->SetStopAgentTracingTaskRunner( |
- BrowserThread::GetBlockingPool()); |
- additional_tracing_agents_.push_back( |
- chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()); |
+ if (debug_daemon) { |
+ debug_daemon->StartAgentTracing( |
+ trace_config, |
+ base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked, |
+ base::Unretained(this))); |
+ ++pending_start_tracing_ack_count_; |
} |
#elif defined(OS_WIN) |
- if (EtwSystemEventConsumer::GetInstance()->StartAgentTracing( |
- trace_config)) { |
- additional_tracing_agents_.push_back( |
- EtwSystemEventConsumer::GetInstance()); |
- } |
+ EtwSystemEventConsumer::GetInstance()->StartAgentTracing( |
+ trace_config, |
+ base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked, |
+ base::Unretained(this))); |
+ ++pending_start_tracing_ack_count_; |
#endif |
} |
// TraceLog may have been enabled in startup tracing before threads are ready. |
if (TraceLog::GetInstance()->IsEnabled()) |
return true; |
- return StartAgentTracing(trace_config); |
+ |
+ StartAgentTracing(trace_config, |
+ base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked, |
+ base::Unretained(this))); |
+ ++pending_start_tracing_ack_count_; |
+ |
+ // Set a deadline to ensure all agents ack within a reasonable time frame. |
+ start_tracing_timer_.Start( |
+ FROM_HERE, base::TimeDelta::FromSeconds(kStartTracingTimeoutSeconds), |
+ base::Bind(&TracingControllerImpl::OnAllTracingAgentsStarted, |
+ base::Unretained(this))); |
+ |
+ return true; |
} |
-void TracingControllerImpl::OnStartAgentTracingDone( |
- const TraceConfig& trace_config) { |
+void TracingControllerImpl::OnAllTracingAgentsStarted() { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
TRACE_EVENT_API_ADD_METADATA_EVENT("IsTimeTicksHighResolution", "value", |
base::TimeTicks::IsHighResolution()); |
- TRACE_EVENT_API_ADD_METADATA_EVENT("TraceConfig", "value", |
- trace_config.AsConvertableToTraceFormat()); |
+ TRACE_EVENT_API_ADD_METADATA_EVENT( |
+ "TraceConfig", "value", |
+ start_tracing_trace_config_->AsConvertableToTraceFormat()); |
// Notify all child processes. |
for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); |
it != trace_message_filters_.end(); ++it) { |
- it->get()->SendBeginTracing(trace_config); |
+ it->get()->SendBeginTracing(*start_tracing_trace_config_); |
} |
- if (!start_tracing_done_callback_.is_null()) { |
+ if (!start_tracing_done_callback_.is_null()) |
start_tracing_done_callback_.Run(); |
- start_tracing_done_callback_.Reset(); |
- } |
+ |
+ start_tracing_done_callback_.Reset(); |
+ start_tracing_trace_config_.reset(); |
} |
bool TracingControllerImpl::StopTracing( |
const scoped_refptr<TraceDataSink>& trace_data_sink) { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ if (!can_stop_tracing()) |
+ return false; |
+ |
+ // If we're still waiting to start tracing, try again after a delay. |
+ if (start_tracing_timer_.IsRunning()) { |
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(base::IgnoreResult(&TracingControllerImpl::StopTracing), |
+ base::Unretained(this), trace_data_sink), |
+ base::TimeDelta::FromMilliseconds(kStopTracingRetryTimeMilliseconds)); |
+ return true; |
+ } |
+ |
if (trace_data_sink) { |
if (TraceLog::GetInstance()->GetCurrentTraceConfig() |
.IsArgumentFilterEnabled()) { |
@@ -290,9 +329,6 @@ bool TracingControllerImpl::StopTracing( |
trace_data_sink->AddMetadata(*GenerateTracingMetadataDict().get()); |
} |
- if (!can_stop_tracing()) |
- return false; |
- |
trace_data_sink_ = trace_data_sink; |
// Issue clock sync marker before actually stopping tracing. |
@@ -649,6 +685,51 @@ void TracingControllerImpl::RemoveTraceMessageFilter( |
trace_message_filters_.erase(trace_message_filter); |
} |
+void TracingControllerImpl::AddTracingAgent(const std::string& agent_name) { |
+#if defined(OS_CHROMEOS) |
+ auto debug_daemon = |
+ chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); |
+ if (agent_name == debug_daemon->GetTracingAgentName()) { |
+ additional_tracing_agents_.push_back(debug_daemon); |
+ debug_daemon->SetStopAgentTracingTaskRunner( |
+ BrowserThread::GetBlockingPool()); |
+ return; |
+ } |
+#elif defined(OS_WIN) |
+ auto etw_agent = EtwSystemEventConsumer::GetInstance(); |
+ if (agent_name == etw_agent->GetTracingAgentName()) { |
+ additional_tracing_agents_.push_back(etw_agent); |
+ return; |
+ } |
+#endif |
+ |
+ auto power_agent = PowerTracingAgent::GetInstance(); |
+ if (agent_name == power_agent->GetTracingAgentName()) { |
+ additional_tracing_agents_.push_back(power_agent); |
+ return; |
+ } |
+ |
+ DCHECK(agent_name == kChromeTracingAgentName); |
+} |
+ |
+void TracingControllerImpl::OnStartAgentTracingAcked( |
+ const std::string& agent_name, |
+ bool success) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ // Don't taken any further action if the ack came after the deadline. |
+ if (!start_tracing_timer_.IsRunning()) |
+ return; |
+ |
+ if (success) |
+ AddTracingAgent(agent_name); |
+ |
+ if (--pending_start_tracing_ack_count_ == 0) { |
+ start_tracing_timer_.Stop(); |
+ OnAllTracingAgentsStarted(); |
+ } |
+} |
+ |
void TracingControllerImpl::OnStopTracingAcked( |
TraceMessageFilter* trace_message_filter, |
const std::vector<std::string>& known_category_groups) { |
@@ -890,28 +971,25 @@ std::string TracingControllerImpl::GetTraceEventLabel() { |
return kChromeTraceLabel; |
} |
-bool TracingControllerImpl::StartAgentTracing( |
- const base::trace_event::TraceConfig& trace_config) { |
+void TracingControllerImpl::StartAgentTracing( |
+ const base::trace_event::TraceConfig& trace_config, |
+ const StartAgentTracingCallback& callback) { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- base::Closure on_start_tracing_done_callback = |
- base::Bind(&TracingControllerImpl::OnStartAgentTracingDone, |
- base::Unretained(this), trace_config); |
+ base::Closure on_agent_started = |
+ base::Bind(callback, kChromeTracingAgentName, true); |
if (!BrowserThread::PostTask( |
BrowserThread::FILE, FROM_HERE, |
base::Bind(&TracingControllerImpl::SetEnabledOnFileThread, |
base::Unretained(this), trace_config, |
base::trace_event::TraceLog::RECORDING_MODE, |
- on_start_tracing_done_callback))) { |
+ on_agent_started))) { |
// BrowserThread::PostTask fails if the threads haven't been created yet, |
// so it should be safe to just use TraceLog::SetEnabled directly. |
base::trace_event::TraceLog::GetInstance()->SetEnabled( |
trace_config, base::trace_event::TraceLog::RECORDING_MODE); |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- on_start_tracing_done_callback); |
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, on_agent_started); |
} |
- |
- return true; |
} |
void TracingControllerImpl::StopAgentTracing( |