| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 #include "content/browser/tracing/tracing_controller_impl.h" | 4 #include "content/browser/tracing/tracing_controller_impl.h" |
| 5 | 5 |
| 6 #include <algorithm> | 6 #include <algorithm> |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/cpu.h" | 12 #include "base/cpu.h" |
| 13 #include "base/files/file_util.h" | 13 #include "base/files/file_util.h" |
| 14 #include "base/guid.h" | 14 #include "base/guid.h" |
| 15 #include "base/json/string_escape.h" | 15 #include "base/json/string_escape.h" |
| 16 #include "base/macros.h" | 16 #include "base/macros.h" |
| 17 #include "base/memory/ref_counted_memory.h" | 17 #include "base/memory/ref_counted_memory.h" |
| 18 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 19 #include "base/strings/string_split.h" |
| 19 #include "base/sys_info.h" | 20 #include "base/sys_info.h" |
| 20 #include "base/threading/sequenced_worker_pool.h" | 21 #include "base/threading/sequenced_worker_pool.h" |
| 21 #include "base/threading/thread_task_runner_handle.h" | 22 #include "base/threading/thread_task_runner_handle.h" |
| 22 #include "base/time/time.h" | 23 #include "base/time/time.h" |
| 23 #include "base/trace_event/trace_event.h" | 24 #include "base/trace_event/trace_event.h" |
| 24 #include "build/build_config.h" | 25 #include "build/build_config.h" |
| 25 #include "components/tracing/common/process_metrics_memory_dump_provider.h" | 26 #include "components/tracing/common/process_metrics_memory_dump_provider.h" |
| 26 #include "content/browser/tracing/file_tracing_provider_impl.h" | 27 #include "content/browser/tracing/file_tracing_provider_impl.h" |
| 27 #include "content/browser/tracing/trace_message_filter.h" | 28 #include "content/browser/tracing/trace_message_filter.h" |
| 28 #include "content/browser/tracing/tracing_ui.h" | 29 #include "content/browser/tracing/tracing_ui.h" |
| 29 #include "content/common/child_process_messages.h" | 30 #include "content/common/child_process_messages.h" |
| 30 #include "content/public/browser/browser_message_filter.h" | 31 #include "content/public/browser/browser_message_filter.h" |
| 31 #include "content/public/browser/content_browser_client.h" | 32 #include "content/public/browser/content_browser_client.h" |
| 32 #include "content/public/browser/gpu_data_manager.h" | 33 #include "content/public/browser/gpu_data_manager.h" |
| 33 #include "content/public/browser/tracing_delegate.h" | 34 #include "content/public/browser/tracing_delegate.h" |
| 34 #include "content/public/common/child_process_host.h" | 35 #include "content/public/common/child_process_host.h" |
| 35 #include "content/public/common/content_client.h" | 36 #include "content/public/common/content_client.h" |
| 36 #include "content/public/common/content_switches.h" | 37 #include "content/public/common/content_switches.h" |
| 37 #include "gpu/config/gpu_info.h" | 38 #include "gpu/config/gpu_info.h" |
| 38 #include "net/base/network_change_notifier.h" | 39 #include "net/base/network_change_notifier.h" |
| 40 #include "services/resource_coordinator/tracing/coordinator_impl.h" |
| 41 #include "services/service_manager/public/cpp/connector.h" |
| 39 #include "v8/include/v8-version-string.h" | 42 #include "v8/include/v8-version-string.h" |
| 40 | 43 |
| 41 #if (defined(OS_POSIX) && defined(USE_UDEV)) || defined(OS_WIN) || \ | 44 #if (defined(OS_POSIX) && defined(USE_UDEV)) || defined(OS_WIN) || \ |
| 42 defined(OS_MACOSX) | 45 defined(OS_MACOSX) |
| 43 #define ENABLE_POWER_TRACING | 46 #define ENABLE_POWER_TRACING |
| 44 #endif | 47 #endif |
| 45 | 48 |
| 46 #if defined(ENABLE_POWER_TRACING) | 49 #if defined(ENABLE_POWER_TRACING) |
| 47 #include "content/browser/tracing/power_tracing_agent.h" | 50 #include "content/browser/tracing/power_tracing_agent.h" |
| 48 #endif | 51 #endif |
| (...skipping 11 matching lines...) Expand all Loading... |
| 60 using base::trace_event::TraceLog; | 63 using base::trace_event::TraceLog; |
| 61 using base::trace_event::TraceConfig; | 64 using base::trace_event::TraceConfig; |
| 62 | 65 |
| 63 namespace content { | 66 namespace content { |
| 64 | 67 |
| 65 namespace { | 68 namespace { |
| 66 | 69 |
| 67 base::LazyInstance<TracingControllerImpl>::Leaky g_controller = | 70 base::LazyInstance<TracingControllerImpl>::Leaky g_controller = |
| 68 LAZY_INSTANCE_INITIALIZER; | 71 LAZY_INSTANCE_INITIALIZER; |
| 69 | 72 |
| 70 const char kChromeTracingAgentName[] = "chrome"; | |
| 71 const char kETWTracingAgentName[] = "etw"; | |
| 72 const char kArcTracingAgentName[] = "arc"; | |
| 73 const char kChromeTraceLabel[] = "traceEvents"; | |
| 74 | |
| 75 const int kStartTracingTimeoutSeconds = 30; | |
| 76 const int kIssueClockSyncTimeoutSeconds = 30; | |
| 77 const int kStopTracingRetryTimeMilliseconds = 100; | |
| 78 | |
| 79 std::string GetNetworkTypeString() { | |
| 80 switch (net::NetworkChangeNotifier::GetConnectionType()) { | |
| 81 case net::NetworkChangeNotifier::CONNECTION_ETHERNET: | |
| 82 return "Ethernet"; | |
| 83 case net::NetworkChangeNotifier::CONNECTION_WIFI: | |
| 84 return "WiFi"; | |
| 85 case net::NetworkChangeNotifier::CONNECTION_2G: | |
| 86 return "2G"; | |
| 87 case net::NetworkChangeNotifier::CONNECTION_3G: | |
| 88 return "3G"; | |
| 89 case net::NetworkChangeNotifier::CONNECTION_4G: | |
| 90 return "4G"; | |
| 91 case net::NetworkChangeNotifier::CONNECTION_NONE: | |
| 92 return "None"; | |
| 93 case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH: | |
| 94 return "Bluetooth"; | |
| 95 case net::NetworkChangeNotifier::CONNECTION_UNKNOWN: | |
| 96 default: | |
| 97 break; | |
| 98 } | |
| 99 return "Unknown"; | |
| 100 } | |
| 101 | |
| 102 std::string GetClockString() { | |
| 103 switch (base::TimeTicks::GetClock()) { | |
| 104 case base::TimeTicks::Clock::LINUX_CLOCK_MONOTONIC: | |
| 105 return "LINUX_CLOCK_MONOTONIC"; | |
| 106 case base::TimeTicks::Clock::IOS_CF_ABSOLUTE_TIME_MINUS_KERN_BOOTTIME: | |
| 107 return "IOS_CF_ABSOLUTE_TIME_MINUS_KERN_BOOTTIME"; | |
| 108 case base::TimeTicks::Clock::MAC_MACH_ABSOLUTE_TIME: | |
| 109 return "MAC_MACH_ABSOLUTE_TIME"; | |
| 110 case base::TimeTicks::Clock::WIN_QPC: | |
| 111 return "WIN_QPC"; | |
| 112 case base::TimeTicks::Clock::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME: | |
| 113 return "WIN_ROLLOVER_PROTECTED_TIME_GET_TIME"; | |
| 114 } | |
| 115 | |
| 116 NOTREACHED(); | |
| 117 return std::string(); | |
| 118 } | |
| 119 | |
| 120 } // namespace | 73 } // namespace |
| 121 | 74 |
| 122 TracingController* TracingController::GetInstance() { | 75 TracingController* TracingController::GetInstance() { |
| 123 return TracingControllerImpl::GetInstance(); | 76 return TracingControllerImpl::GetInstance(); |
| 124 } | 77 } |
| 125 | 78 |
| 126 TracingControllerImpl::TracingControllerImpl() | 79 TracingControllerImpl::TracingControllerImpl() { |
| 127 : pending_start_tracing_ack_count_(0), | |
| 128 pending_stop_tracing_ack_count_(0), | |
| 129 pending_trace_log_status_ack_count_(0), | |
| 130 maximum_trace_buffer_usage_(0), | |
| 131 approximate_event_count_(0), | |
| 132 pending_clock_sync_ack_count_(0), | |
| 133 enabled_tracing_modes_(0) { | |
| 134 // Deliberately leaked, like this class. | 80 // Deliberately leaked, like this class. |
| 135 base::FileTracing::SetProvider(new FileTracingProviderImpl); | 81 base::FileTracing::SetProvider(new FileTracingProviderImpl); |
| 136 } | 82 } |
| 137 | 83 |
| 84 void TracingControllerImpl::Initialize(service_manager::Connector* connector) { |
| 85 if (connector) { |
| 86 connector->BindInterface("tracing", &coordinator_); |
| 87 return; |
| 88 } |
| 89 // If connector is null, the coordinator must be running in this process. |
| 90 resource_coordinator::tracing::CoordinatorImpl* coordinator = |
| 91 resource_coordinator::tracing::CoordinatorImpl::GetInstance(); |
| 92 DCHECK(coordinator); |
| 93 coordinator->BindCoordinatorRequest(mojo::MakeRequest(&coordinator_)); |
| 94 } |
| 95 |
| 138 TracingControllerImpl::~TracingControllerImpl() { | 96 TracingControllerImpl::~TracingControllerImpl() { |
| 139 // This is a Leaky instance. | 97 // This is a Leaky instance. |
| 140 NOTREACHED(); | 98 NOTREACHED(); |
| 141 } | 99 } |
| 142 | 100 |
| 143 TracingControllerImpl* TracingControllerImpl::GetInstance() { | 101 TracingControllerImpl* TracingControllerImpl::GetInstance() { |
| 144 return g_controller.Pointer(); | 102 return g_controller.Pointer(); |
| 145 } | 103 } |
| 146 | 104 |
| 147 bool TracingControllerImpl::GetCategories( | 105 bool TracingControllerImpl::GetCategories( |
| 148 const GetCategoriesDoneCallback& callback) { | 106 const GetCategoriesDoneCallback& callback) { |
| 149 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 107 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 150 | 108 |
| 151 // Known categories come back from child processes with the EndTracingAck | 109 coordinator_->GetCategories( |
| 152 // message. So to get known categories, just begin and end tracing immediately | 110 base::BindRepeating(&TracingControllerImpl::GetCategoriesDone, |
| 153 // afterwards. This will ping all the child processes for categories. | 111 base::Unretained(this), callback)); |
| 154 pending_get_categories_done_callback_ = callback; | |
| 155 if (!StartTracing(TraceConfig("*", ""), StartTracingDoneCallback())) { | |
| 156 pending_get_categories_done_callback_.Reset(); | |
| 157 return false; | |
| 158 } | |
| 159 | |
| 160 bool ok = StopTracing(NULL); | |
| 161 DCHECK(ok); | |
| 162 return true; | 112 return true; |
| 163 } | 113 } |
| 164 | 114 |
| 165 void TracingControllerImpl::SetEnabledOnFileThread( | 115 void TracingControllerImpl::GetCategoriesDone( |
| 166 const TraceConfig& trace_config, | 116 const GetCategoriesDoneCallback& callback, |
| 167 const base::Closure& callback) { | 117 const std::string& categories) { |
| 168 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 118 const std::vector<std::string> split = base::SplitString( |
| 169 | 119 categories, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| 170 TraceLog::GetInstance()->SetEnabled(trace_config, enabled_tracing_modes_); | 120 std::set<std::string> category_set; |
| 171 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | 121 for (const auto& category : split) { |
| 172 } | 122 category_set.insert(category); |
| 173 | 123 } |
| 174 void TracingControllerImpl::SetDisabledOnFileThread( | 124 callback.Run(category_set); |
| 175 const base::Closure& callback) { | |
| 176 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
| 177 | |
| 178 DCHECK(enabled_tracing_modes_); | |
| 179 TraceLog::GetInstance()->SetDisabled(enabled_tracing_modes_); | |
| 180 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | |
| 181 } | 125 } |
| 182 | 126 |
| 183 bool TracingControllerImpl::StartTracing( | 127 bool TracingControllerImpl::StartTracing( |
| 184 const TraceConfig& trace_config, | 128 const TraceConfig& trace_config, |
| 185 const StartTracingDoneCallback& callback) { | 129 const StartTracingDoneCallback& callback) { |
| 186 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 130 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 187 DCHECK(additional_tracing_agents_.empty()); | |
| 188 | 131 |
| 189 // TODO(ssid): Introduce a priority for tracing agents to handle multiple | 132 is_tracing_ = true; |
| 190 // start and stop requests, crbug.com/705087. | 133 mojo::DataPipe data_pipe; |
| 191 if (!can_start_tracing()) | 134 coordinator_->StartTracing(std::move(data_pipe.producer_handle), |
| 192 return false; | 135 trace_config.ToString()); |
| 193 start_tracing_done_callback_ = callback; | 136 drainer_.reset(new mojo::common::DataPipeDrainer( |
| 194 trace_config_.reset(new base::trace_event::TraceConfig(trace_config)); | 137 this, std::move(data_pipe.consumer_handle))); |
| 195 enabled_tracing_modes_ = TraceLog::RECORDING_MODE; | 138 if (!callback.is_null()) |
| 196 if (!trace_config_->event_filters().empty()) | 139 callback.Run(); |
| 197 enabled_tracing_modes_ |= TraceLog::FILTERING_MODE; | |
| 198 metadata_.reset(new base::DictionaryValue()); | |
| 199 pending_start_tracing_ack_count_ = 0; | |
| 200 | |
| 201 #if defined(OS_ANDROID) | |
| 202 if (pending_get_categories_done_callback_.is_null()) | |
| 203 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); | |
| 204 #endif | |
| 205 | |
| 206 if (trace_config.IsSystraceEnabled()) { | |
| 207 #if defined(ENABLE_POWER_TRACING) | |
| 208 PowerTracingAgent::GetInstance()->StartAgentTracing( | |
| 209 trace_config, | |
| 210 base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked, | |
| 211 base::Unretained(this))); | |
| 212 ++pending_start_tracing_ack_count_; | |
| 213 #endif | |
| 214 | |
| 215 #if defined(OS_CHROMEOS) | |
| 216 chromeos::DebugDaemonClient* debug_daemon = | |
| 217 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); | |
| 218 if (debug_daemon) { | |
| 219 debug_daemon->StartAgentTracing( | |
| 220 trace_config, | |
| 221 base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked, | |
| 222 base::Unretained(this))); | |
| 223 ++pending_start_tracing_ack_count_; | |
| 224 } | |
| 225 | |
| 226 ArcTracingAgent::GetInstance()->StartAgentTracing( | |
| 227 trace_config, | |
| 228 base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked, | |
| 229 base::Unretained(this))); | |
| 230 ++pending_start_tracing_ack_count_; | |
| 231 #elif defined(OS_WIN) | |
| 232 EtwTracingAgent::GetInstance()->StartAgentTracing( | |
| 233 trace_config, | |
| 234 base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked, | |
| 235 base::Unretained(this))); | |
| 236 ++pending_start_tracing_ack_count_; | |
| 237 #endif | |
| 238 } | |
| 239 | |
| 240 // TraceLog may have been enabled in startup tracing before threads are ready. | |
| 241 if (TraceLog::GetInstance()->IsEnabled()) | |
| 242 return true; | |
| 243 | |
| 244 StartAgentTracing(trace_config, | |
| 245 base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked, | |
| 246 base::Unretained(this))); | |
| 247 ++pending_start_tracing_ack_count_; | |
| 248 | |
| 249 // Set a deadline to ensure all agents ack within a reasonable time frame. | |
| 250 start_tracing_timer_.Start( | |
| 251 FROM_HERE, base::TimeDelta::FromSeconds(kStartTracingTimeoutSeconds), | |
| 252 base::Bind(&TracingControllerImpl::OnAllTracingAgentsStarted, | |
| 253 base::Unretained(this))); | |
| 254 | |
| 255 return true; | 140 return true; |
| 256 } | 141 } |
| 257 | 142 |
| 258 void TracingControllerImpl::OnAllTracingAgentsStarted() { | |
| 259 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 260 | |
| 261 TRACE_EVENT_API_ADD_METADATA_EVENT( | |
| 262 TraceLog::GetCategoryGroupEnabled("__metadata"), | |
| 263 "IsTimeTicksHighResolution", "value", | |
| 264 base::TimeTicks::IsHighResolution()); | |
| 265 | |
| 266 // Notify all child processes. | |
| 267 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); | |
| 268 it != trace_message_filters_.end(); ++it) { | |
| 269 it->get()->SendBeginTracing(*trace_config_); | |
| 270 } | |
| 271 | |
| 272 if (!start_tracing_done_callback_.is_null()) | |
| 273 start_tracing_done_callback_.Run(); | |
| 274 | |
| 275 start_tracing_done_callback_.Reset(); | |
| 276 } | |
| 277 | |
| 278 void TracingControllerImpl::AddMetadata(const base::DictionaryValue& data) { | |
| 279 if (metadata_) | |
| 280 metadata_->MergeDictionary(&data); | |
| 281 } | |
| 282 | |
| 283 bool TracingControllerImpl::StopTracing( | 143 bool TracingControllerImpl::StopTracing( |
| 284 const scoped_refptr<TraceDataSink>& trace_data_sink) { | 144 const scoped_refptr<TraceDataSink>& trace_data_sink) { |
| 285 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 145 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 286 | 146 |
| 287 if (!can_stop_tracing()) | |
| 288 return false; | |
| 289 | |
| 290 // If we're still waiting to start tracing, try again after a delay. | |
| 291 if (start_tracing_timer_.IsRunning()) { | |
| 292 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 293 FROM_HERE, | |
| 294 base::Bind(base::IgnoreResult(&TracingControllerImpl::StopTracing), | |
| 295 base::Unretained(this), trace_data_sink), | |
| 296 base::TimeDelta::FromMilliseconds(kStopTracingRetryTimeMilliseconds)); | |
| 297 return true; | |
| 298 } | |
| 299 | |
| 300 if (trace_data_sink) { | |
| 301 MetadataFilterPredicate metadata_filter; | |
| 302 if (TraceLog::GetInstance()->GetCurrentTraceConfig() | |
| 303 .IsArgumentFilterEnabled()) { | |
| 304 std::unique_ptr<TracingDelegate> delegate( | |
| 305 GetContentClient()->browser()->GetTracingDelegate()); | |
| 306 if (delegate) | |
| 307 metadata_filter = delegate->GetMetadataFilterPredicate(); | |
| 308 } | |
| 309 AddFilteredMetadata(trace_data_sink.get(), GenerateTracingMetadataDict(), | |
| 310 metadata_filter); | |
| 311 AddFilteredMetadata(trace_data_sink.get(), std::move(metadata_), | |
| 312 metadata_filter); | |
| 313 } else { | |
| 314 metadata_.reset(); | |
| 315 } | |
| 316 | |
| 317 trace_data_sink_ = trace_data_sink; | 147 trace_data_sink_ = trace_data_sink; |
| 318 trace_config_.reset(); | 148 coordinator_->StopAndFlush(); |
| 319 | |
| 320 // Issue clock sync marker before actually stopping tracing. | |
| 321 // StopTracingAfterClockSync() will be called after clock sync is done. | |
| 322 IssueClockSyncMarker(); | |
| 323 | |
| 324 return true; | 149 return true; |
| 325 } | 150 } |
| 326 | 151 |
| 327 void TracingControllerImpl::StopTracingAfterClockSync() { | |
| 328 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 329 | |
| 330 // |pending_clock_sync_ack_count_| could be non-zero if clock sync times out. | |
| 331 pending_clock_sync_ack_count_ = 0; | |
| 332 | |
| 333 // Disable local trace early to avoid traces during end-tracing process from | |
| 334 // interfering with the process. | |
| 335 base::Closure on_stop_tracing_done_callback = base::Bind( | |
| 336 &TracingControllerImpl::OnStopTracingDone, base::Unretained(this)); | |
| 337 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
| 338 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread, | |
| 339 base::Unretained(this), | |
| 340 on_stop_tracing_done_callback)); | |
| 341 } | |
| 342 | |
| 343 void TracingControllerImpl::OnStopTracingDone() { | |
| 344 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 345 | |
| 346 #if defined(OS_ANDROID) | |
| 347 if (pending_get_categories_done_callback_.is_null()) | |
| 348 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); | |
| 349 #endif | |
| 350 | |
| 351 // Count myself (local trace) in pending_stop_tracing_ack_count_, | |
| 352 // acked below. | |
| 353 pending_stop_tracing_ack_count_ = trace_message_filters_.size() + 1; | |
| 354 pending_stop_tracing_filters_ = trace_message_filters_; | |
| 355 | |
| 356 pending_stop_tracing_ack_count_ += additional_tracing_agents_.size(); | |
| 357 for (auto* it : additional_tracing_agents_) { | |
| 358 it->StopAgentTracing( | |
| 359 base::Bind(&TracingControllerImpl::OnEndAgentTracingAcked, | |
| 360 base::Unretained(this))); | |
| 361 } | |
| 362 additional_tracing_agents_.clear(); | |
| 363 | |
| 364 StopAgentTracing(StopAgentTracingCallback()); | |
| 365 } | |
| 366 | |
| 367 bool TracingControllerImpl::GetTraceBufferUsage( | 152 bool TracingControllerImpl::GetTraceBufferUsage( |
| 368 const GetTraceBufferUsageCallback& callback) { | 153 const GetTraceBufferUsageCallback& callback) { |
| 369 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 154 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 370 | 155 |
| 371 if (!can_get_trace_buffer_usage() || callback.is_null()) | 156 coordinator_->RequestBufferUsage( |
| 372 return false; | 157 base::BindRepeating(&TracingControllerImpl::GetTraceBufferUsageDone, |
| 373 | 158 base::Unretained(this), callback)); |
| 374 pending_trace_buffer_usage_callback_ = callback; | |
| 375 | |
| 376 // Count myself in pending_trace_log_status_ack_count_, acked below. | |
| 377 pending_trace_log_status_ack_count_ = trace_message_filters_.size() + 1; | |
| 378 pending_trace_log_status_filters_ = trace_message_filters_; | |
| 379 maximum_trace_buffer_usage_ = 0; | |
| 380 approximate_event_count_ = 0; | |
| 381 | |
| 382 base::trace_event::TraceLogStatus status = | |
| 383 TraceLog::GetInstance()->GetStatus(); | |
| 384 // Call OnTraceLogStatusReply unconditionally for the browser process. | |
| 385 // This will result in immediate execution of the callback if there are no | |
| 386 // child processes. | |
| 387 BrowserThread::PostTask( | |
| 388 BrowserThread::UI, FROM_HERE, | |
| 389 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply, | |
| 390 base::Unretained(this), nullptr, status)); | |
| 391 | |
| 392 // Notify all child processes. | |
| 393 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); | |
| 394 it != trace_message_filters_.end(); ++it) { | |
| 395 it->get()->SendGetTraceLogStatus(); | |
| 396 } | |
| 397 return true; | 159 return true; |
| 398 } | 160 } |
| 399 | 161 |
| 162 void TracingControllerImpl::AddMetadata(const base::DictionaryValue& metadata) { |
| 163 if (metadata_) |
| 164 metadata_->MergeDictionary(&metadata); |
| 165 } |
| 166 |
| 400 bool TracingControllerImpl::IsTracing() const { | 167 bool TracingControllerImpl::IsTracing() const { |
| 401 return !!enabled_tracing_modes_; | 168 return is_tracing_; |
| 169 } |
| 170 |
| 171 void TracingControllerImpl::GetTraceBufferUsageDone( |
| 172 const GetTraceBufferUsageCallback& callback, |
| 173 bool success, |
| 174 float percent_full, |
| 175 uint32_t approximate_count) { |
| 176 callback.Run(percent_full, approximate_count); |
| 402 } | 177 } |
| 403 | 178 |
| 404 void TracingControllerImpl::AddTraceMessageFilter( | 179 void TracingControllerImpl::AddTraceMessageFilter( |
| 405 TraceMessageFilter* trace_message_filter) { | 180 TraceMessageFilter* trace_message_filter) { |
| 406 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 181 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 407 BrowserThread::PostTask( | 182 BrowserThread::PostTask( |
| 408 BrowserThread::UI, FROM_HERE, | 183 BrowserThread::UI, FROM_HERE, |
| 409 base::Bind(&TracingControllerImpl::AddTraceMessageFilter, | 184 base::Bind(&TracingControllerImpl::AddTraceMessageFilter, |
| 410 base::Unretained(this), | 185 base::Unretained(this), |
| 411 base::RetainedRef(trace_message_filter))); | 186 base::RetainedRef(trace_message_filter))); |
| 412 return; | 187 return; |
| 413 } | 188 } |
| 414 | 189 |
| 415 #if defined(OS_LINUX) | 190 #if defined(OS_LINUX) |
| 416 // On Linux the browser process dumps process metrics for child process due to | 191 // On Linux the browser process dumps process metrics for child process due to |
| 417 // sandbox. | 192 // sandbox. |
| 418 tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess( | 193 tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess( |
| 419 trace_message_filter->peer_pid()); | 194 trace_message_filter->peer_pid()); |
| 420 #endif | 195 #endif |
| 421 | 196 |
| 422 trace_message_filters_.insert(trace_message_filter); | 197 trace_message_filters_.insert(trace_message_filter); |
| 423 if (can_stop_tracing()) { | |
| 424 trace_message_filter->SendBeginTracing( | |
| 425 TraceLog::GetInstance()->GetCurrentTraceConfig()); | |
| 426 } | |
| 427 | |
| 428 for (auto& observer : trace_message_filter_observers_) | 198 for (auto& observer : trace_message_filter_observers_) |
| 429 observer.OnTraceMessageFilterAdded(trace_message_filter); | 199 observer.OnTraceMessageFilterAdded(trace_message_filter); |
| 430 } | 200 } |
| 431 | 201 |
| 432 void TracingControllerImpl::RemoveTraceMessageFilter( | 202 void TracingControllerImpl::RemoveTraceMessageFilter( |
| 433 TraceMessageFilter* trace_message_filter) { | 203 TraceMessageFilter* trace_message_filter) { |
| 434 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 204 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 435 BrowserThread::PostTask( | 205 BrowserThread::PostTask( |
| 436 BrowserThread::UI, FROM_HERE, | 206 BrowserThread::UI, FROM_HERE, |
| 437 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter, | 207 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter, |
| 438 base::Unretained(this), | 208 base::Unretained(this), |
| 439 base::RetainedRef(trace_message_filter))); | 209 base::RetainedRef(trace_message_filter))); |
| 440 return; | 210 return; |
| 441 } | 211 } |
| 442 | 212 |
| 443 #if defined(OS_LINUX) | 213 #if defined(OS_LINUX) |
| 444 tracing::ProcessMetricsMemoryDumpProvider::UnregisterForProcess( | 214 tracing::ProcessMetricsMemoryDumpProvider::UnregisterForProcess( |
| 445 trace_message_filter->peer_pid()); | 215 trace_message_filter->peer_pid()); |
| 446 #endif | 216 #endif |
| 447 | 217 |
| 448 // If a filter is removed while a response from that filter is pending then | |
| 449 // simulate the response. Otherwise the response count will be wrong and the | |
| 450 // completion callback will never be executed. | |
| 451 if (pending_stop_tracing_ack_count_ > 0) { | |
| 452 TraceMessageFilterSet::const_iterator it = | |
| 453 pending_stop_tracing_filters_.find(trace_message_filter); | |
| 454 if (it != pending_stop_tracing_filters_.end()) { | |
| 455 BrowserThread::PostTask( | |
| 456 BrowserThread::UI, FROM_HERE, | |
| 457 base::Bind(&TracingControllerImpl::OnStopTracingAcked, | |
| 458 base::Unretained(this), | |
| 459 base::RetainedRef(trace_message_filter), | |
| 460 std::vector<std::string>())); | |
| 461 } | |
| 462 } | |
| 463 if (pending_trace_log_status_ack_count_ > 0) { | |
| 464 TraceMessageFilterSet::const_iterator it = | |
| 465 pending_trace_log_status_filters_.find(trace_message_filter); | |
| 466 if (it != pending_trace_log_status_filters_.end()) { | |
| 467 BrowserThread::PostTask( | |
| 468 BrowserThread::UI, FROM_HERE, | |
| 469 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply, | |
| 470 base::Unretained(this), | |
| 471 base::RetainedRef(trace_message_filter), | |
| 472 base::trace_event::TraceLogStatus())); | |
| 473 } | |
| 474 } | |
| 475 trace_message_filters_.erase(trace_message_filter); | 218 trace_message_filters_.erase(trace_message_filter); |
| 476 } | 219 } |
| 477 | 220 |
| 478 void TracingControllerImpl::AddTracingAgent(const std::string& agent_name) { | |
| 479 #if defined(OS_CHROMEOS) | |
| 480 auto* debug_daemon = | |
| 481 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); | |
| 482 if (agent_name == debug_daemon->GetTracingAgentName()) { | |
| 483 additional_tracing_agents_.push_back(debug_daemon); | |
| 484 debug_daemon->SetStopAgentTracingTaskRunner( | |
| 485 BrowserThread::GetBlockingPool()); | |
| 486 return; | |
| 487 } | |
| 488 | |
| 489 if (agent_name == kArcTracingAgentName) { | |
| 490 additional_tracing_agents_.push_back(ArcTracingAgent::GetInstance()); | |
| 491 return; | |
| 492 } | |
| 493 #elif defined(OS_WIN) | |
| 494 auto* etw_agent = EtwTracingAgent::GetInstance(); | |
| 495 if (agent_name == etw_agent->GetTracingAgentName()) { | |
| 496 additional_tracing_agents_.push_back(etw_agent); | |
| 497 return; | |
| 498 } | |
| 499 #endif | |
| 500 | |
| 501 #if defined(ENABLE_POWER_TRACING) | |
| 502 auto* power_agent = PowerTracingAgent::GetInstance(); | |
| 503 if (agent_name == power_agent->GetTracingAgentName()) { | |
| 504 additional_tracing_agents_.push_back(power_agent); | |
| 505 return; | |
| 506 } | |
| 507 #endif | |
| 508 | |
| 509 DCHECK(agent_name == kChromeTracingAgentName); | |
| 510 } | |
| 511 | |
| 512 void TracingControllerImpl::OnStartAgentTracingAcked( | |
| 513 const std::string& agent_name, | |
| 514 bool success) { | |
| 515 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 516 | |
| 517 // Don't taken any further action if the ack came after the deadline. | |
| 518 if (!start_tracing_timer_.IsRunning()) | |
| 519 return; | |
| 520 | |
| 521 if (success) | |
| 522 AddTracingAgent(agent_name); | |
| 523 | |
| 524 if (--pending_start_tracing_ack_count_ == 0) { | |
| 525 start_tracing_timer_.Stop(); | |
| 526 OnAllTracingAgentsStarted(); | |
| 527 } | |
| 528 } | |
| 529 | |
| 530 void TracingControllerImpl::OnStopTracingAcked( | |
| 531 TraceMessageFilter* trace_message_filter, | |
| 532 const std::vector<std::string>& known_category_groups) { | |
| 533 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
| 534 BrowserThread::PostTask( | |
| 535 BrowserThread::UI, FROM_HERE, | |
| 536 base::Bind( | |
| 537 &TracingControllerImpl::OnStopTracingAcked, base::Unretained(this), | |
| 538 base::RetainedRef(trace_message_filter), known_category_groups)); | |
| 539 return; | |
| 540 } | |
| 541 | |
| 542 // Merge known_category_groups with known_category_groups_ | |
| 543 known_category_groups_.insert(known_category_groups.begin(), | |
| 544 known_category_groups.end()); | |
| 545 | |
| 546 if (pending_stop_tracing_ack_count_ == 0) | |
| 547 return; | |
| 548 | |
| 549 if (trace_message_filter && | |
| 550 !pending_stop_tracing_filters_.erase(trace_message_filter)) { | |
| 551 // The response from the specified message filter has already been received. | |
| 552 return; | |
| 553 } | |
| 554 | |
| 555 if (--pending_stop_tracing_ack_count_ == 1) { | |
| 556 // All acks from subprocesses have been received. Now flush the local trace. | |
| 557 // During or after this call, our OnLocalTraceDataCollected will be | |
| 558 // called with the last of the local trace data. | |
| 559 if (trace_data_sink_) { | |
| 560 TraceLog::GetInstance()->Flush( | |
| 561 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected, | |
| 562 base::Unretained(this)), | |
| 563 true); | |
| 564 } else { | |
| 565 TraceLog::GetInstance()->CancelTracing( | |
| 566 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected, | |
| 567 base::Unretained(this))); | |
| 568 } | |
| 569 return; | |
| 570 } | |
| 571 | |
| 572 if (pending_stop_tracing_ack_count_ != 0) | |
| 573 return; | |
| 574 | |
| 575 // All acks (including from the subprocesses and the local trace) have been | |
| 576 // received. | |
| 577 enabled_tracing_modes_ = 0; | |
| 578 | |
| 579 // Trigger callback if one is set. | |
| 580 if (!pending_get_categories_done_callback_.is_null()) { | |
| 581 pending_get_categories_done_callback_.Run(known_category_groups_); | |
| 582 pending_get_categories_done_callback_.Reset(); | |
| 583 } else if (trace_data_sink_.get()) { | |
| 584 trace_data_sink_->Close(); | |
| 585 trace_data_sink_ = NULL; | |
| 586 } | |
| 587 } | |
| 588 | |
| 589 void TracingControllerImpl::OnEndAgentTracingAcked( | |
| 590 const std::string& agent_name, | |
| 591 const std::string& events_label, | |
| 592 const scoped_refptr<base::RefCountedString>& events_str_ptr) { | |
| 593 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 594 | |
| 595 if (trace_data_sink_.get() && events_str_ptr && | |
| 596 !events_str_ptr->data().empty()) { | |
| 597 if (agent_name == kETWTracingAgentName) { | |
| 598 // The Windows kernel events are kept into a JSON format stored as string | |
| 599 // and must not be escaped. | |
| 600 trace_data_sink_->AddAgentTrace(events_label, events_str_ptr->data()); | |
| 601 } else if (agent_name == kArcTracingAgentName) { | |
| 602 // The ARC events are kept into a JSON format stored as string | |
| 603 // and must not be escaped. | |
| 604 trace_data_sink_->AddTraceChunk(events_str_ptr->data()); | |
| 605 } else { | |
| 606 trace_data_sink_->AddAgentTrace( | |
| 607 events_label, base::GetQuotedJSONString(events_str_ptr->data())); | |
| 608 } | |
| 609 } | |
| 610 std::vector<std::string> category_groups; | |
| 611 OnStopTracingAcked(NULL, category_groups); | |
| 612 } | |
| 613 | |
| 614 void TracingControllerImpl::OnTraceDataCollected( | |
| 615 const scoped_refptr<base::RefCountedString>& events_str_ptr) { | |
| 616 // OnTraceDataCollected may be called from any browser thread, either by the | |
| 617 // local event trace system or from child processes via TraceMessageFilter. | |
| 618 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
| 619 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 620 base::Bind(&TracingControllerImpl::OnTraceDataCollected, | |
| 621 base::Unretained(this), events_str_ptr)); | |
| 622 return; | |
| 623 } | |
| 624 | |
| 625 if (trace_data_sink_.get()) | |
| 626 trace_data_sink_->AddTraceChunk(events_str_ptr->data()); | |
| 627 } | |
| 628 | |
| 629 void TracingControllerImpl::OnLocalTraceDataCollected( | |
| 630 const scoped_refptr<base::RefCountedString>& events_str_ptr, | |
| 631 bool has_more_events) { | |
| 632 if (events_str_ptr->data().size()) | |
| 633 OnTraceDataCollected(events_str_ptr); | |
| 634 | |
| 635 if (has_more_events) | |
| 636 return; | |
| 637 | |
| 638 // Simulate an StopTracingAcked for the local trace. | |
| 639 std::vector<std::string> category_groups; | |
| 640 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups); | |
| 641 OnStopTracingAcked(NULL, category_groups); | |
| 642 } | |
| 643 | |
| 644 void TracingControllerImpl::OnTraceLogStatusReply( | |
| 645 TraceMessageFilter* trace_message_filter, | |
| 646 const base::trace_event::TraceLogStatus& status) { | |
| 647 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
| 648 BrowserThread::PostTask( | |
| 649 BrowserThread::UI, FROM_HERE, | |
| 650 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply, | |
| 651 base::Unretained(this), | |
| 652 base::RetainedRef(trace_message_filter), status)); | |
| 653 return; | |
| 654 } | |
| 655 | |
| 656 if (pending_trace_log_status_ack_count_ == 0) | |
| 657 return; | |
| 658 | |
| 659 if (trace_message_filter && | |
| 660 !pending_trace_log_status_filters_.erase(trace_message_filter)) { | |
| 661 // The response from the specified message filter has already been received. | |
| 662 return; | |
| 663 } | |
| 664 | |
| 665 float percent_full = static_cast<float>( | |
| 666 static_cast<double>(status.event_count) / status.event_capacity); | |
| 667 maximum_trace_buffer_usage_ = | |
| 668 std::max(maximum_trace_buffer_usage_, percent_full); | |
| 669 approximate_event_count_ += status.event_count; | |
| 670 | |
| 671 if (--pending_trace_log_status_ack_count_ == 0) { | |
| 672 // Trigger callback if one is set. | |
| 673 pending_trace_buffer_usage_callback_.Run(maximum_trace_buffer_usage_, | |
| 674 approximate_event_count_); | |
| 675 pending_trace_buffer_usage_callback_.Reset(); | |
| 676 } | |
| 677 } | |
| 678 | |
| 679 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) { | 221 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) { |
| 680 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end()); | 222 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end()); |
| 681 tracing_uis_.insert(tracing_ui); | 223 tracing_uis_.insert(tracing_ui); |
| 682 } | 224 } |
| 683 | 225 |
| 684 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) { | 226 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) { |
| 685 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui); | 227 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui); |
| 686 DCHECK(it != tracing_uis_.end()); | 228 DCHECK(it != tracing_uis_.end()); |
| 687 tracing_uis_.erase(it); | 229 tracing_uis_.erase(it); |
| 688 } | 230 } |
| 689 | 231 |
| 690 std::string TracingControllerImpl::GetTracingAgentName() { | |
| 691 return kChromeTracingAgentName; | |
| 692 } | |
| 693 | |
| 694 std::string TracingControllerImpl::GetTraceEventLabel() { | |
| 695 return kChromeTraceLabel; | |
| 696 } | |
| 697 | |
| 698 void TracingControllerImpl::StartAgentTracing( | |
| 699 const base::trace_event::TraceConfig& trace_config, | |
| 700 const StartAgentTracingCallback& callback) { | |
| 701 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 702 | |
| 703 base::Closure on_agent_started = | |
| 704 base::Bind(callback, kChromeTracingAgentName, true); | |
| 705 if (!BrowserThread::PostTask( | |
| 706 BrowserThread::FILE, FROM_HERE, | |
| 707 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread, | |
| 708 base::Unretained(this), trace_config, | |
| 709 on_agent_started))) { | |
| 710 // BrowserThread::PostTask fails if the threads haven't been created yet, | |
| 711 // so it should be safe to just use TraceLog::SetEnabled directly. | |
| 712 TraceLog::GetInstance()->SetEnabled(trace_config, enabled_tracing_modes_); | |
| 713 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, on_agent_started); | |
| 714 } | |
| 715 } | |
| 716 | |
| 717 void TracingControllerImpl::StopAgentTracing( | |
| 718 const StopAgentTracingCallback& callback) { | |
| 719 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 720 // Handle special case of zero child processes by immediately flushing the | |
| 721 // trace log. Once the flush has completed the caller will be notified that | |
| 722 // tracing has ended. | |
| 723 if (pending_stop_tracing_ack_count_ == 1) { | |
| 724 // Flush/cancel asynchronously now, because we don't have any children to | |
| 725 // wait for. | |
| 726 if (trace_data_sink_) { | |
| 727 TraceLog::GetInstance()->Flush( | |
| 728 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected, | |
| 729 base::Unretained(this)), | |
| 730 true); | |
| 731 } else { | |
| 732 TraceLog::GetInstance()->CancelTracing( | |
| 733 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected, | |
| 734 base::Unretained(this))); | |
| 735 } | |
| 736 } | |
| 737 | |
| 738 // Notify all child processes. | |
| 739 for (auto it : trace_message_filters_) { | |
| 740 if (trace_data_sink_) | |
| 741 it->SendEndTracing(); | |
| 742 else | |
| 743 it->SendCancelTracing(); | |
| 744 } | |
| 745 } | |
| 746 | |
| 747 bool TracingControllerImpl::SupportsExplicitClockSync() { | |
| 748 return true; | |
| 749 } | |
| 750 | |
| 751 void TracingControllerImpl::RecordClockSyncMarker( | |
| 752 const std::string& sync_id, | |
| 753 const RecordClockSyncMarkerCallback& callback) { | |
| 754 DCHECK(SupportsExplicitClockSync()); | |
| 755 | |
| 756 TRACE_EVENT_CLOCK_SYNC_RECEIVER(sync_id); | |
| 757 } | |
| 758 | |
| 759 void TracingControllerImpl::IssueClockSyncMarker() { | |
| 760 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 761 DCHECK_EQ(0, pending_clock_sync_ack_count_); | |
| 762 | |
| 763 for (auto* it : additional_tracing_agents_) { | |
| 764 if (it->SupportsExplicitClockSync()) { | |
| 765 it->RecordClockSyncMarker( | |
| 766 base::GenerateGUID(), | |
| 767 base::Bind(&TracingControllerImpl::OnClockSyncMarkerRecordedByAgent, | |
| 768 base::Unretained(this))); | |
| 769 pending_clock_sync_ack_count_++; | |
| 770 } | |
| 771 } | |
| 772 | |
| 773 // If no clock sync is needed, stop tracing right away. Otherwise, schedule | |
| 774 // to stop tracing after timeout. | |
| 775 if (pending_clock_sync_ack_count_ == 0) { | |
| 776 StopTracingAfterClockSync(); | |
| 777 } else { | |
| 778 clock_sync_timer_.Start( | |
| 779 FROM_HERE, base::TimeDelta::FromSeconds(kIssueClockSyncTimeoutSeconds), | |
| 780 this, &TracingControllerImpl::StopTracingAfterClockSync); | |
| 781 } | |
| 782 } | |
| 783 | |
| 784 void TracingControllerImpl::OnClockSyncMarkerRecordedByAgent( | |
| 785 const std::string& sync_id, | |
| 786 const base::TimeTicks& issue_ts, | |
| 787 const base::TimeTicks& issue_end_ts) { | |
| 788 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 789 | |
| 790 // TODO(charliea): Change this function so that it can accept a boolean | |
| 791 // success indicator instead of having to rely on sentinel issue_ts and | |
| 792 // issue_end_ts values to signal failure. | |
| 793 if (!(issue_ts == base::TimeTicks() || issue_end_ts == base::TimeTicks())) | |
| 794 TRACE_EVENT_CLOCK_SYNC_ISSUER(sync_id, issue_ts, issue_end_ts); | |
| 795 | |
| 796 // Timer is not running means that clock sync already timed out. | |
| 797 if (!clock_sync_timer_.IsRunning()) | |
| 798 return; | |
| 799 | |
| 800 // Stop tracing only if all agents report back. | |
| 801 if (--pending_clock_sync_ack_count_ == 0) { | |
| 802 clock_sync_timer_.Stop(); | |
| 803 StopTracingAfterClockSync(); | |
| 804 } | |
| 805 } | |
| 806 | |
| 807 void TracingControllerImpl::AddFilteredMetadata( | |
| 808 TracingController::TraceDataSink* sink, | |
| 809 std::unique_ptr<base::DictionaryValue> metadata, | |
| 810 const MetadataFilterPredicate& filter) { | |
| 811 if (filter.is_null()) { | |
| 812 sink->AddMetadata(std::move(metadata)); | |
| 813 return; | |
| 814 } | |
| 815 std::unique_ptr<base::DictionaryValue> filtered_metadata( | |
| 816 new base::DictionaryValue); | |
| 817 for (base::DictionaryValue::Iterator it(*metadata); !it.IsAtEnd(); | |
| 818 it.Advance()) { | |
| 819 if (filter.Run(it.key())) | |
| 820 filtered_metadata->Set(it.key(), it.value().DeepCopy()); | |
| 821 else | |
| 822 filtered_metadata->SetString(it.key(), "__stripped__"); | |
| 823 } | |
| 824 sink->AddMetadata(std::move(filtered_metadata)); | |
| 825 } | |
| 826 | |
| 827 std::unique_ptr<base::DictionaryValue> | |
| 828 TracingControllerImpl::GenerateTracingMetadataDict() const { | |
| 829 // It's important that this function creates a new metadata dict and returns | |
| 830 // it rather than directly populating the metadata_ member, as the data may | |
| 831 // need filtering in some cases. | |
| 832 std::unique_ptr<base::DictionaryValue> metadata_dict( | |
| 833 new base::DictionaryValue()); | |
| 834 | |
| 835 metadata_dict->SetString("network-type", GetNetworkTypeString()); | |
| 836 metadata_dict->SetString("product-version", GetContentClient()->GetProduct()); | |
| 837 metadata_dict->SetString("v8-version", V8_VERSION_STRING); | |
| 838 metadata_dict->SetString("user-agent", GetContentClient()->GetUserAgent()); | |
| 839 | |
| 840 // OS | |
| 841 #if defined(OS_CHROMEOS) | |
| 842 metadata_dict->SetString("os-name", "CrOS"); | |
| 843 int32_t major_version; | |
| 844 int32_t minor_version; | |
| 845 int32_t bugfix_version; | |
| 846 // OperatingSystemVersion only has a POSIX implementation which returns the | |
| 847 // wrong versions for CrOS. | |
| 848 base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, | |
| 849 &bugfix_version); | |
| 850 metadata_dict->SetString( | |
| 851 "os-version", base::StringPrintf("%d.%d.%d", major_version, minor_version, | |
| 852 bugfix_version)); | |
| 853 #else | |
| 854 metadata_dict->SetString("os-name", base::SysInfo::OperatingSystemName()); | |
| 855 metadata_dict->SetString("os-version", | |
| 856 base::SysInfo::OperatingSystemVersion()); | |
| 857 #endif | |
| 858 metadata_dict->SetString("os-arch", | |
| 859 base::SysInfo::OperatingSystemArchitecture()); | |
| 860 | |
| 861 // CPU | |
| 862 base::CPU cpu; | |
| 863 metadata_dict->SetInteger("cpu-family", cpu.family()); | |
| 864 metadata_dict->SetInteger("cpu-model", cpu.model()); | |
| 865 metadata_dict->SetInteger("cpu-stepping", cpu.stepping()); | |
| 866 metadata_dict->SetInteger("num-cpus", base::SysInfo::NumberOfProcessors()); | |
| 867 metadata_dict->SetInteger("physical-memory", | |
| 868 base::SysInfo::AmountOfPhysicalMemoryMB()); | |
| 869 | |
| 870 std::string cpu_brand = cpu.cpu_brand(); | |
| 871 // Workaround for crbug.com/249713. | |
| 872 // TODO(oysteine): Remove workaround when bug is fixed. | |
| 873 size_t null_pos = cpu_brand.find('\0'); | |
| 874 if (null_pos != std::string::npos) | |
| 875 cpu_brand.erase(null_pos); | |
| 876 metadata_dict->SetString("cpu-brand", cpu_brand); | |
| 877 | |
| 878 // GPU | |
| 879 gpu::GPUInfo gpu_info = content::GpuDataManager::GetInstance()->GetGPUInfo(); | |
| 880 | |
| 881 #if !defined(OS_ANDROID) | |
| 882 metadata_dict->SetInteger("gpu-venid", gpu_info.gpu.vendor_id); | |
| 883 metadata_dict->SetInteger("gpu-devid", gpu_info.gpu.device_id); | |
| 884 #endif | |
| 885 | |
| 886 metadata_dict->SetString("gpu-driver", gpu_info.driver_version); | |
| 887 metadata_dict->SetString("gpu-psver", gpu_info.pixel_shader_version); | |
| 888 metadata_dict->SetString("gpu-vsver", gpu_info.vertex_shader_version); | |
| 889 | |
| 890 #if defined(OS_MACOSX) | |
| 891 metadata_dict->SetString("gpu-glver", gpu_info.gl_version); | |
| 892 #elif defined(OS_POSIX) | |
| 893 metadata_dict->SetString("gpu-gl-vendor", gpu_info.gl_vendor); | |
| 894 metadata_dict->SetString("gpu-gl-renderer", gpu_info.gl_renderer); | |
| 895 #endif | |
| 896 | |
| 897 std::unique_ptr<TracingDelegate> delegate( | |
| 898 GetContentClient()->browser()->GetTracingDelegate()); | |
| 899 if (delegate) | |
| 900 delegate->GenerateMetadataDict(metadata_dict.get()); | |
| 901 | |
| 902 metadata_dict->SetString("clock-domain", GetClockString()); | |
| 903 metadata_dict->SetBoolean("highres-ticks", | |
| 904 base::TimeTicks::IsHighResolution()); | |
| 905 | |
| 906 metadata_dict->SetString("trace-config", trace_config_->ToString()); | |
| 907 | |
| 908 metadata_dict->SetString( | |
| 909 "command_line", | |
| 910 base::CommandLine::ForCurrentProcess()->GetCommandLineString()); | |
| 911 | |
| 912 base::Time::Exploded ctime; | |
| 913 base::Time::Now().UTCExplode(&ctime); | |
| 914 std::string time_string = base::StringPrintf( | |
| 915 "%u-%u-%u %d:%d:%d", ctime.year, ctime.month, ctime.day_of_month, | |
| 916 ctime.hour, ctime.minute, ctime.second); | |
| 917 metadata_dict->SetString("trace-capture-datetime", time_string); | |
| 918 | |
| 919 return metadata_dict; | |
| 920 } | |
| 921 | |
| 922 void TracingControllerImpl::AddTraceMessageFilterObserver( | 232 void TracingControllerImpl::AddTraceMessageFilterObserver( |
| 923 TraceMessageFilterObserver* observer) { | 233 TraceMessageFilterObserver* observer) { |
| 924 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 234 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 925 trace_message_filter_observers_.AddObserver(observer); | 235 trace_message_filter_observers_.AddObserver(observer); |
| 926 | 236 |
| 927 for (auto& filter : trace_message_filters_) | 237 for (auto& filter : trace_message_filters_) |
| 928 observer->OnTraceMessageFilterAdded(filter.get()); | 238 observer->OnTraceMessageFilterAdded(filter.get()); |
| 929 } | 239 } |
| 930 | 240 |
| 931 void TracingControllerImpl::RemoveTraceMessageFilterObserver( | 241 void TracingControllerImpl::RemoveTraceMessageFilterObserver( |
| 932 TraceMessageFilterObserver* observer) { | 242 TraceMessageFilterObserver* observer) { |
| 933 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 243 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 934 trace_message_filter_observers_.RemoveObserver(observer); | 244 trace_message_filter_observers_.RemoveObserver(observer); |
| 935 | 245 |
| 936 for (auto& filter : trace_message_filters_) | 246 for (auto& filter : trace_message_filters_) |
| 937 observer->OnTraceMessageFilterRemoved(filter.get()); | 247 observer->OnTraceMessageFilterRemoved(filter.get()); |
| 938 } | 248 } |
| 939 | 249 |
| 250 void TracingControllerImpl::OnDataAvailable(const void* data, |
| 251 size_t num_bytes) { |
| 252 if (trace_data_sink_.get()) { |
| 253 const std::string chunk(static_cast<const char*>(data), num_bytes); |
| 254 trace_data_sink_->AddTraceChunk(chunk); |
| 255 } |
| 256 } |
| 257 |
| 258 void TracingControllerImpl::OnDataComplete() { |
| 259 is_tracing_ = false; |
| 260 if (trace_data_sink_.get()) { |
| 261 trace_data_sink_->Close(); |
| 262 trace_data_sink_ = NULL; |
| 263 } |
| 264 } |
| 265 |
| 940 } // namespace content | 266 } // namespace content |
| OLD | NEW |