Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / tracing / tracing_controller_impl.cc
blob7b1452f982d1f0700fbf16cc553ba7011bdaa8c3
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
3 // found in the LICENSE file.
4 #include "content/browser/tracing/tracing_controller_impl.h"
6 #include "base/bind.h"
7 #include "base/files/file_util.h"
8 #include "base/json/string_escape.h"
9 #include "base/macros.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/trace_event/trace_event.h"
12 #include "content/browser/tracing/file_tracing_provider_impl.h"
13 #include "content/browser/tracing/trace_message_filter.h"
14 #include "content/browser/tracing/tracing_ui.h"
15 #include "content/common/child_process_messages.h"
16 #include "content/public/browser/browser_message_filter.h"
17 #include "content/public/common/content_switches.h"
19 #if defined(OS_CHROMEOS)
20 #include "chromeos/dbus/dbus_thread_manager.h"
21 #include "chromeos/dbus/debug_daemon_client.h"
22 #endif
24 #if defined(OS_WIN)
25 #include "content/browser/tracing/etw_system_event_consumer_win.h"
26 #endif
28 using base::trace_event::TraceLog;
29 using base::trace_event::TraceConfig;
31 namespace content {
33 namespace {
35 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
36 LAZY_INSTANCE_INITIALIZER;
38 } // namespace
40 TracingController* TracingController::GetInstance() {
41 return TracingControllerImpl::GetInstance();
44 TracingControllerImpl::TracingControllerImpl()
45 : pending_disable_recording_ack_count_(0),
46 pending_capture_monitoring_snapshot_ack_count_(0),
47 pending_trace_log_status_ack_count_(0),
48 maximum_trace_buffer_usage_(0),
49 approximate_event_count_(0),
50 pending_memory_dump_ack_count_(0),
51 failed_memory_dump_count_(0),
52 // Tracing may have been enabled by ContentMainRunner if kTraceStartup
53 // is specified in command line.
54 #if defined(OS_CHROMEOS) || defined(OS_WIN)
55 is_system_tracing_(false),
56 #endif
57 is_recording_(TraceLog::GetInstance()->IsEnabled()),
58 is_monitoring_(false) {
59 base::trace_event::MemoryDumpManager::GetInstance()->SetDelegate(this);
61 // Deliberately leaked, like this class.
62 base::FileTracing::SetProvider(new FileTracingProviderImpl);
65 TracingControllerImpl::~TracingControllerImpl() {
66 // This is a Leaky instance.
67 NOTREACHED();
70 TracingControllerImpl* TracingControllerImpl::GetInstance() {
71 return g_controller.Pointer();
74 bool TracingControllerImpl::GetCategories(
75 const GetCategoriesDoneCallback& callback) {
76 DCHECK_CURRENTLY_ON(BrowserThread::UI);
78 // Known categories come back from child processes with the EndTracingAck
79 // message. So to get known categories, just begin and end tracing immediately
80 // afterwards. This will ping all the child processes for categories.
81 pending_get_categories_done_callback_ = callback;
82 if (!EnableRecording(TraceConfig("*", ""), EnableRecordingDoneCallback())) {
83 pending_get_categories_done_callback_.Reset();
84 return false;
87 bool ok = DisableRecording(NULL);
88 DCHECK(ok);
89 return true;
92 void TracingControllerImpl::SetEnabledOnFileThread(
93 const TraceConfig& trace_config,
94 int mode,
95 const base::Closure& callback) {
96 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
98 TraceLog::GetInstance()->SetEnabled(
99 trace_config, static_cast<TraceLog::Mode>(mode));
100 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
103 void TracingControllerImpl::SetDisabledOnFileThread(
104 const base::Closure& callback) {
105 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
107 TraceLog::GetInstance()->SetDisabled();
108 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
111 bool TracingControllerImpl::EnableRecording(
112 const TraceConfig& trace_config,
113 const EnableRecordingDoneCallback& callback) {
114 DCHECK_CURRENTLY_ON(BrowserThread::UI);
116 if (!can_enable_recording())
117 return false;
118 is_recording_ = true;
120 #if defined(OS_ANDROID)
121 if (pending_get_categories_done_callback_.is_null())
122 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
123 #endif
125 if (trace_config.IsSystraceEnabled()) {
126 #if defined(OS_CHROMEOS)
127 DCHECK(!is_system_tracing_);
128 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
129 StartSystemTracing();
130 is_system_tracing_ = true;
131 #elif defined(OS_WIN)
132 DCHECK(!is_system_tracing_);
133 is_system_tracing_ =
134 EtwSystemEventConsumer::GetInstance()->StartSystemTracing();
135 #endif
139 base::Closure on_enable_recording_done_callback =
140 base::Bind(&TracingControllerImpl::OnEnableRecordingDone,
141 base::Unretained(this),
142 trace_config, callback);
143 if (!BrowserThread::PostTask(
144 BrowserThread::FILE, FROM_HERE,
145 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
146 base::Unretained(this), trace_config,
147 base::trace_event::TraceLog::RECORDING_MODE,
148 on_enable_recording_done_callback))) {
149 // BrowserThread::PostTask fails if the threads haven't been created yet,
150 // so it should be safe to just use TraceLog::SetEnabled directly.
151 base::trace_event::TraceLog::GetInstance()->SetEnabled(
152 trace_config, base::trace_event::TraceLog::RECORDING_MODE);
153 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
154 on_enable_recording_done_callback);
157 return true;
160 void TracingControllerImpl::OnEnableRecordingDone(
161 const TraceConfig& trace_config,
162 const EnableRecordingDoneCallback& callback) {
163 DCHECK_CURRENTLY_ON(BrowserThread::UI);
165 // Notify all child processes.
166 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
167 it != trace_message_filters_.end(); ++it) {
168 it->get()->SendBeginTracing(trace_config);
171 if (!callback.is_null())
172 callback.Run();
175 bool TracingControllerImpl::DisableRecording(
176 const scoped_refptr<TraceDataSink>& trace_data_sink) {
177 DCHECK_CURRENTLY_ON(BrowserThread::UI);
179 if (!can_disable_recording())
180 return false;
182 trace_data_sink_ = trace_data_sink;
183 // Disable local trace early to avoid traces during end-tracing process from
184 // interfering with the process.
185 base::Closure on_disable_recording_done_callback = base::Bind(
186 &TracingControllerImpl::OnDisableRecordingDone, base::Unretained(this));
187 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
188 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
189 base::Unretained(this),
190 on_disable_recording_done_callback));
191 return true;
194 void TracingControllerImpl::OnDisableRecordingDone() {
195 DCHECK_CURRENTLY_ON(BrowserThread::UI);
197 #if defined(OS_ANDROID)
198 if (pending_get_categories_done_callback_.is_null())
199 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
200 #endif
202 // Count myself (local trace) in pending_disable_recording_ack_count_,
203 // acked below.
204 pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
205 pending_disable_recording_filters_ = trace_message_filters_;
207 #if defined(OS_CHROMEOS) || defined(OS_WIN)
208 if (is_system_tracing_) {
209 // Disable system tracing.
210 is_system_tracing_ = false;
211 ++pending_disable_recording_ack_count_;
213 #if defined(OS_CHROMEOS)
214 scoped_refptr<base::TaskRunner> task_runner =
215 BrowserThread::GetBlockingPool();
216 chromeos::DBusThreadManager::Get()
217 ->GetDebugDaemonClient()
218 ->RequestStopSystemTracing(
219 task_runner,
220 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
221 base::Unretained(this)));
222 #elif defined(OS_WIN)
223 EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
224 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
225 base::Unretained(this)));
226 #endif
228 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
230 // Handle special case of zero child processes by immediately flushing the
231 // trace log. Once the flush has completed the caller will be notified that
232 // tracing has ended.
233 if (pending_disable_recording_ack_count_ == 1) {
234 // Flush/cancel asynchronously now, because we don't have any children to
235 // wait for.
236 if (trace_data_sink_) {
237 TraceLog::GetInstance()->Flush(
238 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
239 base::Unretained(this)),
240 true);
241 } else {
242 TraceLog::GetInstance()->CancelTracing(
243 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
244 base::Unretained(this)));
248 // Notify all child processes.
249 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
250 it != trace_message_filters_.end(); ++it) {
251 if (trace_data_sink_)
252 it->get()->SendEndTracing();
253 else
254 it->get()->SendCancelTracing();
258 bool TracingControllerImpl::EnableMonitoring(
259 const TraceConfig& trace_config,
260 const EnableMonitoringDoneCallback& callback) {
261 DCHECK_CURRENTLY_ON(BrowserThread::UI);
263 if (!can_enable_monitoring())
264 return false;
265 OnMonitoringStateChanged(true);
267 #if defined(OS_ANDROID)
268 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
269 #endif
271 base::Closure on_enable_monitoring_done_callback =
272 base::Bind(&TracingControllerImpl::OnEnableMonitoringDone,
273 base::Unretained(this),
274 trace_config, callback);
275 if (!BrowserThread::PostTask(
276 BrowserThread::FILE, FROM_HERE,
277 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
278 base::Unretained(this), trace_config,
279 base::trace_event::TraceLog::MONITORING_MODE,
280 on_enable_monitoring_done_callback))) {
281 // BrowserThread::PostTask fails if the threads haven't been created yet,
282 // so it should be safe to just use TraceLog::SetEnabled directly.
283 base::trace_event::TraceLog::GetInstance()->SetEnabled(
284 trace_config, base::trace_event::TraceLog::MONITORING_MODE);
285 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
286 on_enable_monitoring_done_callback);
288 return true;
291 void TracingControllerImpl::OnEnableMonitoringDone(
292 const TraceConfig& trace_config,
293 const EnableMonitoringDoneCallback& callback) {
294 DCHECK_CURRENTLY_ON(BrowserThread::UI);
296 // Notify all child processes.
297 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
298 it != trace_message_filters_.end(); ++it) {
299 it->get()->SendEnableMonitoring(trace_config);
302 if (!callback.is_null())
303 callback.Run();
306 bool TracingControllerImpl::DisableMonitoring(
307 const DisableMonitoringDoneCallback& callback) {
308 DCHECK_CURRENTLY_ON(BrowserThread::UI);
310 if (!can_disable_monitoring())
311 return false;
313 base::Closure on_disable_monitoring_done_callback =
314 base::Bind(&TracingControllerImpl::OnDisableMonitoringDone,
315 base::Unretained(this), callback);
316 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
317 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
318 base::Unretained(this),
319 on_disable_monitoring_done_callback));
320 return true;
323 void TracingControllerImpl::OnDisableMonitoringDone(
324 const DisableMonitoringDoneCallback& callback) {
325 DCHECK_CURRENTLY_ON(BrowserThread::UI);
327 OnMonitoringStateChanged(false);
329 // Notify all child processes.
330 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
331 it != trace_message_filters_.end(); ++it) {
332 it->get()->SendDisableMonitoring();
334 if (!callback.is_null())
335 callback.Run();
338 void TracingControllerImpl::GetMonitoringStatus(
339 bool* out_enabled,
340 TraceConfig* out_trace_config) {
341 *out_enabled = is_monitoring_;
342 *out_trace_config = TraceLog::GetInstance()->GetCurrentTraceConfig();
345 bool TracingControllerImpl::CaptureMonitoringSnapshot(
346 const scoped_refptr<TraceDataSink>& monitoring_data_sink) {
347 DCHECK_CURRENTLY_ON(BrowserThread::UI);
349 if (!can_disable_monitoring())
350 return false;
352 if (!monitoring_data_sink.get())
353 return false;
355 monitoring_data_sink_ = monitoring_data_sink;
357 // Count myself in pending_capture_monitoring_snapshot_ack_count_,
358 // acked below.
359 pending_capture_monitoring_snapshot_ack_count_ =
360 trace_message_filters_.size() + 1;
361 pending_capture_monitoring_filters_ = trace_message_filters_;
363 // Handle special case of zero child processes by immediately flushing the
364 // trace log. Once the flush has completed the caller will be notified that
365 // the capture snapshot has ended.
366 if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
367 // Flush asynchronously now, because we don't have any children to wait for.
368 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
369 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
370 base::Unretained(this)));
373 // Notify all child processes.
374 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
375 it != trace_message_filters_.end(); ++it) {
376 it->get()->SendCaptureMonitoringSnapshot();
379 #if defined(OS_ANDROID)
380 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
381 #endif
383 return true;
386 bool TracingControllerImpl::GetTraceBufferUsage(
387 const GetTraceBufferUsageCallback& callback) {
388 DCHECK_CURRENTLY_ON(BrowserThread::UI);
390 if (!can_get_trace_buffer_usage() || callback.is_null())
391 return false;
393 pending_trace_buffer_usage_callback_ = callback;
395 // Count myself in pending_trace_log_status_ack_count_, acked below.
396 pending_trace_log_status_ack_count_ = trace_message_filters_.size() + 1;
397 pending_trace_log_status_filters_ = trace_message_filters_;
398 maximum_trace_buffer_usage_ = 0;
399 approximate_event_count_ = 0;
401 base::trace_event::TraceLogStatus status =
402 TraceLog::GetInstance()->GetStatus();
403 // Call OnTraceLogStatusReply unconditionally for the browser process.
404 // This will result in immediate execution of the callback if there are no
405 // child processes.
406 BrowserThread::PostTask(
407 BrowserThread::UI, FROM_HERE,
408 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
409 base::Unretained(this), scoped_refptr<TraceMessageFilter>(),
410 status));
412 // Notify all child processes.
413 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
414 it != trace_message_filters_.end(); ++it) {
415 it->get()->SendGetTraceLogStatus();
417 return true;
420 bool TracingControllerImpl::SetWatchEvent(
421 const std::string& category_name,
422 const std::string& event_name,
423 const WatchEventCallback& callback) {
424 DCHECK_CURRENTLY_ON(BrowserThread::UI);
426 if (callback.is_null())
427 return false;
429 watch_category_name_ = category_name;
430 watch_event_name_ = event_name;
431 watch_event_callback_ = callback;
433 TraceLog::GetInstance()->SetWatchEvent(
434 category_name, event_name,
435 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
436 base::Unretained(this)));
438 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
439 it != trace_message_filters_.end(); ++it) {
440 it->get()->SendSetWatchEvent(category_name, event_name);
442 return true;
445 bool TracingControllerImpl::CancelWatchEvent() {
446 DCHECK_CURRENTLY_ON(BrowserThread::UI);
448 if (!can_cancel_watch_event())
449 return false;
451 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
452 it != trace_message_filters_.end(); ++it) {
453 it->get()->SendCancelWatchEvent();
456 watch_event_callback_.Reset();
457 return true;
460 bool TracingControllerImpl::IsRecording() const {
461 return is_recording_;
464 void TracingControllerImpl::AddTraceMessageFilter(
465 TraceMessageFilter* trace_message_filter) {
466 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
467 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
468 base::Bind(&TracingControllerImpl::AddTraceMessageFilter,
469 base::Unretained(this),
470 make_scoped_refptr(trace_message_filter)));
471 return;
474 trace_message_filters_.insert(trace_message_filter);
475 if (can_cancel_watch_event()) {
476 trace_message_filter->SendSetWatchEvent(watch_category_name_,
477 watch_event_name_);
479 if (can_disable_recording()) {
480 trace_message_filter->SendBeginTracing(
481 TraceLog::GetInstance()->GetCurrentTraceConfig());
483 if (can_disable_monitoring()) {
484 trace_message_filter->SendEnableMonitoring(
485 TraceLog::GetInstance()->GetCurrentTraceConfig());
489 void TracingControllerImpl::RemoveTraceMessageFilter(
490 TraceMessageFilter* trace_message_filter) {
491 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
492 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
493 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter,
494 base::Unretained(this),
495 make_scoped_refptr(trace_message_filter)));
496 return;
499 // If a filter is removed while a response from that filter is pending then
500 // simulate the response. Otherwise the response count will be wrong and the
501 // completion callback will never be executed.
502 if (pending_disable_recording_ack_count_ > 0) {
503 TraceMessageFilterSet::const_iterator it =
504 pending_disable_recording_filters_.find(trace_message_filter);
505 if (it != pending_disable_recording_filters_.end()) {
506 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
507 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
508 base::Unretained(this),
509 make_scoped_refptr(trace_message_filter),
510 std::vector<std::string>()));
513 if (pending_capture_monitoring_snapshot_ack_count_ > 0) {
514 TraceMessageFilterSet::const_iterator it =
515 pending_capture_monitoring_filters_.find(trace_message_filter);
516 if (it != pending_capture_monitoring_filters_.end()) {
517 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
518 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
519 base::Unretained(this),
520 make_scoped_refptr(trace_message_filter)));
523 if (pending_trace_log_status_ack_count_ > 0) {
524 TraceMessageFilterSet::const_iterator it =
525 pending_trace_log_status_filters_.find(trace_message_filter);
526 if (it != pending_trace_log_status_filters_.end()) {
527 BrowserThread::PostTask(
528 BrowserThread::UI, FROM_HERE,
529 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
530 base::Unretained(this),
531 make_scoped_refptr(trace_message_filter),
532 base::trace_event::TraceLogStatus()));
535 if (pending_memory_dump_ack_count_ > 0) {
536 TraceMessageFilterSet::const_iterator it =
537 pending_memory_dump_filters_.find(trace_message_filter);
538 if (it != pending_memory_dump_filters_.end()) {
539 BrowserThread::PostTask(
540 BrowserThread::UI, FROM_HERE,
541 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
542 base::Unretained(this),
543 make_scoped_refptr(trace_message_filter),
544 pending_memory_dump_guid_, false /* success */));
547 trace_message_filters_.erase(trace_message_filter);
550 void TracingControllerImpl::OnDisableRecordingAcked(
551 TraceMessageFilter* trace_message_filter,
552 const std::vector<std::string>& known_category_groups) {
553 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
554 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
555 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
556 base::Unretained(this),
557 make_scoped_refptr(trace_message_filter),
558 known_category_groups));
559 return;
562 // Merge known_category_groups with known_category_groups_
563 known_category_groups_.insert(known_category_groups.begin(),
564 known_category_groups.end());
566 if (pending_disable_recording_ack_count_ == 0)
567 return;
569 if (trace_message_filter &&
570 !pending_disable_recording_filters_.erase(trace_message_filter)) {
571 // The response from the specified message filter has already been received.
572 return;
575 if (--pending_disable_recording_ack_count_ == 1) {
576 // All acks from subprocesses have been received. Now flush the local trace.
577 // During or after this call, our OnLocalTraceDataCollected will be
578 // called with the last of the local trace data.
579 if (trace_data_sink_) {
580 TraceLog::GetInstance()->Flush(
581 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
582 base::Unretained(this)),
583 true);
584 } else {
585 TraceLog::GetInstance()->CancelTracing(
586 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
587 base::Unretained(this)));
589 return;
592 if (pending_disable_recording_ack_count_ != 0)
593 return;
595 // All acks (including from the subprocesses and the local trace) have been
596 // received.
597 is_recording_ = false;
599 // Trigger callback if one is set.
600 if (!pending_get_categories_done_callback_.is_null()) {
601 pending_get_categories_done_callback_.Run(known_category_groups_);
602 pending_get_categories_done_callback_.Reset();
603 } else if (trace_data_sink_.get()) {
604 trace_data_sink_->Close();
605 trace_data_sink_ = NULL;
609 #if defined(OS_CHROMEOS) || defined(OS_WIN)
610 void TracingControllerImpl::OnEndSystemTracingAcked(
611 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
612 DCHECK_CURRENTLY_ON(BrowserThread::UI);
614 if (trace_data_sink_.get()) {
615 #if defined(OS_WIN)
616 // The Windows kernel events are kept into a JSon format stored as string
617 // and must not be escaped.
618 std::string json_string = events_str_ptr->data();
619 #else
620 std::string json_string =
621 base::GetQuotedJSONString(events_str_ptr->data());
622 #endif
623 trace_data_sink_->SetSystemTrace(json_string);
625 DCHECK(!is_system_tracing_);
626 std::vector<std::string> category_groups;
627 OnDisableRecordingAcked(NULL, category_groups);
629 #endif
631 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
632 TraceMessageFilter* trace_message_filter) {
633 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
634 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
635 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
636 base::Unretained(this),
637 make_scoped_refptr(trace_message_filter)));
638 return;
641 if (pending_capture_monitoring_snapshot_ack_count_ == 0)
642 return;
644 if (trace_message_filter &&
645 !pending_capture_monitoring_filters_.erase(trace_message_filter)) {
646 // The response from the specified message filter has already been received.
647 return;
650 if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
651 // All acks from subprocesses have been received. Now flush the local trace.
652 // During or after this call, our OnLocalMonitoringTraceDataCollected
653 // will be called with the last of the local trace data.
654 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
655 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
656 base::Unretained(this)));
657 return;
660 if (pending_capture_monitoring_snapshot_ack_count_ != 0)
661 return;
663 if (monitoring_data_sink_.get()) {
664 monitoring_data_sink_->Close();
665 monitoring_data_sink_ = NULL;
669 void TracingControllerImpl::OnTraceDataCollected(
670 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
671 // OnTraceDataCollected may be called from any browser thread, either by the
672 // local event trace system or from child processes via TraceMessageFilter.
673 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
674 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
675 base::Bind(&TracingControllerImpl::OnTraceDataCollected,
676 base::Unretained(this), events_str_ptr));
677 return;
680 if (trace_data_sink_.get())
681 trace_data_sink_->AddTraceChunk(events_str_ptr->data());
684 void TracingControllerImpl::OnMonitoringTraceDataCollected(
685 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
686 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
687 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
688 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
689 base::Unretained(this), events_str_ptr));
690 return;
693 if (monitoring_data_sink_.get())
694 monitoring_data_sink_->AddTraceChunk(events_str_ptr->data());
697 void TracingControllerImpl::OnLocalTraceDataCollected(
698 const scoped_refptr<base::RefCountedString>& events_str_ptr,
699 bool has_more_events) {
700 if (events_str_ptr->data().size())
701 OnTraceDataCollected(events_str_ptr);
703 if (has_more_events)
704 return;
706 // Simulate an DisableRecordingAcked for the local trace.
707 std::vector<std::string> category_groups;
708 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
709 OnDisableRecordingAcked(NULL, category_groups);
712 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
713 const scoped_refptr<base::RefCountedString>& events_str_ptr,
714 bool has_more_events) {
715 if (events_str_ptr->data().size())
716 OnMonitoringTraceDataCollected(events_str_ptr);
718 if (has_more_events)
719 return;
721 // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
722 OnCaptureMonitoringSnapshotAcked(NULL);
725 void TracingControllerImpl::OnTraceLogStatusReply(
726 TraceMessageFilter* trace_message_filter,
727 const base::trace_event::TraceLogStatus& status) {
728 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
729 BrowserThread::PostTask(
730 BrowserThread::UI, FROM_HERE,
731 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
732 base::Unretained(this),
733 make_scoped_refptr(trace_message_filter), status));
734 return;
737 if (pending_trace_log_status_ack_count_ == 0)
738 return;
740 if (trace_message_filter &&
741 !pending_trace_log_status_filters_.erase(trace_message_filter)) {
742 // The response from the specified message filter has already been received.
743 return;
746 float percent_full = static_cast<float>(
747 static_cast<double>(status.event_count) / status.event_capacity);
748 maximum_trace_buffer_usage_ =
749 std::max(maximum_trace_buffer_usage_, percent_full);
750 approximate_event_count_ += status.event_count;
752 if (--pending_trace_log_status_ack_count_ == 0) {
753 // Trigger callback if one is set.
754 pending_trace_buffer_usage_callback_.Run(maximum_trace_buffer_usage_,
755 approximate_event_count_);
756 pending_trace_buffer_usage_callback_.Reset();
760 void TracingControllerImpl::OnWatchEventMatched() {
761 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
762 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
763 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
764 base::Unretained(this)));
765 return;
768 if (!watch_event_callback_.is_null())
769 watch_event_callback_.Run();
772 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) {
773 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end());
774 tracing_uis_.insert(tracing_ui);
777 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) {
778 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui);
779 DCHECK(it != tracing_uis_.end());
780 tracing_uis_.erase(it);
783 void TracingControllerImpl::RequestGlobalMemoryDump(
784 const base::trace_event::MemoryDumpRequestArgs& args,
785 const base::trace_event::MemoryDumpCallback& callback) {
786 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
787 BrowserThread::PostTask(
788 BrowserThread::UI, FROM_HERE,
789 base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump,
790 base::Unretained(this), args, callback));
791 return;
793 // Abort if another dump is already in progress.
794 if (pending_memory_dump_guid_) {
795 DVLOG(1) << "Requested memory dump " << args.dump_guid
796 << " while waiting for " << pending_memory_dump_guid_;
797 if (!callback.is_null())
798 callback.Run(args.dump_guid, false /* success */);
799 return;
802 // Count myself (local trace) in pending_memory_dump_ack_count_, acked by
803 // OnBrowserProcessMemoryDumpDone().
804 pending_memory_dump_ack_count_ = trace_message_filters_.size() + 1;
805 pending_memory_dump_filters_.clear();
806 pending_memory_dump_guid_ = args.dump_guid;
807 pending_memory_dump_callback_ = callback;
808 failed_memory_dump_count_ = 0;
810 MemoryDumpManagerDelegate::CreateProcessDump(
811 args, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone,
812 base::Unretained(this)));
814 // If there are no child processes we are just done.
815 if (pending_memory_dump_ack_count_ == 1)
816 return;
818 pending_memory_dump_filters_ = trace_message_filters_;
820 for (const scoped_refptr<TraceMessageFilter>& tmf : trace_message_filters_)
821 tmf->SendProcessMemoryDumpRequest(args);
824 bool TracingControllerImpl::IsCoordinatorProcess() const {
825 return true;
828 void TracingControllerImpl::OnProcessMemoryDumpResponse(
829 TraceMessageFilter* trace_message_filter,
830 uint64 dump_guid,
831 bool success) {
832 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
833 BrowserThread::PostTask(
834 BrowserThread::UI, FROM_HERE,
835 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
836 base::Unretained(this),
837 make_scoped_refptr(trace_message_filter), dump_guid,
838 success));
839 return;
842 TraceMessageFilterSet::iterator it =
843 pending_memory_dump_filters_.find(trace_message_filter);
845 if (pending_memory_dump_guid_ != dump_guid ||
846 it == pending_memory_dump_filters_.end()) {
847 DLOG(WARNING) << "Received unexpected memory dump response: " << dump_guid;
848 return;
851 DCHECK_GT(pending_memory_dump_ack_count_, 0);
852 --pending_memory_dump_ack_count_;
853 pending_memory_dump_filters_.erase(it);
854 if (!success) {
855 ++failed_memory_dump_count_;
856 DLOG(WARNING) << "Global memory dump failed because of NACK from child "
857 << trace_message_filter->peer_pid();
859 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
862 void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64 dump_guid,
863 bool success) {
864 DCHECK_GT(pending_memory_dump_ack_count_, 0);
865 --pending_memory_dump_ack_count_;
866 if (!success) {
867 ++failed_memory_dump_count_;
868 DLOG(WARNING) << "Global memory dump aborted on the current process";
870 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
873 void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() {
874 if (pending_memory_dump_ack_count_ > 0)
875 return;
877 DCHECK_NE(0u, pending_memory_dump_guid_);
878 const bool global_success = failed_memory_dump_count_ == 0;
879 if (!pending_memory_dump_callback_.is_null()) {
880 pending_memory_dump_callback_.Run(pending_memory_dump_guid_,
881 global_success);
882 pending_memory_dump_callback_.Reset();
884 pending_memory_dump_guid_ = 0;
887 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
888 if (is_monitoring_ == is_monitoring)
889 return;
891 is_monitoring_ = is_monitoring;
892 #if !defined(OS_ANDROID)
893 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin();
894 it != tracing_uis_.end(); it++) {
895 (*it)->OnMonitoringStateChanged(is_monitoring);
897 #endif
900 } // namespace content