| 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 70edf234be4be8849a0883912a32216293d48130..492c9cda33f32221aae5d7289a2da304bcbf3214 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 "content/browser/tracing/file_tracing_provider_impl.h" | 
| @@ -50,7 +52,9 @@ const char kChromeTracingAgentName[] = "chrome"; | 
| const char kETWTracingAgentName[] = "etw"; | 
| const char kChromeTraceLabel[] = "traceEvents"; | 
|  | 
| -const int kIssueClockSyncTimeout = 30; | 
| +const int kStartTracingTimeout = 30; | 
| +const int kIssueClockSyncTimeoutSeconds = 30; | 
| +const int kStopTracingRetryTimeMilliseconds = 100; | 
|  | 
| std::string GetNetworkTypeString() { | 
| switch (net::NetworkChangeNotifier::GetConnectionType()) { | 
| @@ -144,7 +148,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), | 
| @@ -218,6 +223,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()) | 
| @@ -225,57 +233,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(kStartTracingTimeout), | 
| +      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()) { | 
| @@ -289,9 +328,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. | 
| @@ -636,6 +672,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) { | 
| @@ -876,28 +957,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( | 
| @@ -969,7 +1047,7 @@ void TracingControllerImpl::IssueClockSyncMarker() { | 
| } else { | 
| clock_sync_timer_.Start( | 
| FROM_HERE, | 
| -        base::TimeDelta::FromSeconds(kIssueClockSyncTimeout), | 
| +        base::TimeDelta::FromSeconds(kIssueClockSyncTimeoutSeconds), | 
| this, | 
| &TracingControllerImpl::StopTracingAfterClockSync); | 
| } | 
|  |