Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / tracing / tracing_controller_impl.cc
blob68984fada69e6fe5eb62a347a93d46544346be89
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/trace_message_filter.h"
13 #include "content/browser/tracing/tracing_ui.h"
14 #include "content/common/child_process_messages.h"
15 #include "content/public/browser/browser_message_filter.h"
16 #include "content/public/common/content_switches.h"
18 #if defined(OS_CHROMEOS)
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/debug_daemon_client.h"
21 #endif
23 #if defined(OS_WIN)
24 #include "content/browser/tracing/etw_system_event_consumer_win.h"
25 #endif
27 using base::trace_event::TraceLog;
28 using base::trace_event::TraceOptions;
29 using base::trace_event::CategoryFilter;
31 namespace content {
33 namespace {
35 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
36 LAZY_INSTANCE_INITIALIZER;
38 class FileTraceDataSink : public TracingController::TraceDataSink {
39 public:
40 explicit FileTraceDataSink(const base::FilePath& trace_file_path,
41 const base::Closure& callback)
42 : file_path_(trace_file_path),
43 completion_callback_(callback),
44 file_(NULL) {}
46 void AddTraceChunk(const std::string& chunk) override {
47 std::string tmp = chunk;
48 scoped_refptr<base::RefCountedString> chunk_ptr =
49 base::RefCountedString::TakeString(&tmp);
50 BrowserThread::PostTask(
51 BrowserThread::FILE,
52 FROM_HERE,
53 base::Bind(
54 &FileTraceDataSink::AddTraceChunkOnFileThread, this, chunk_ptr));
56 void SetSystemTrace(const std::string& data) override {
57 system_trace_ = data;
59 void Close() override {
60 BrowserThread::PostTask(
61 BrowserThread::FILE,
62 FROM_HERE,
63 base::Bind(&FileTraceDataSink::CloseOnFileThread, this));
66 private:
67 ~FileTraceDataSink() override { DCHECK(file_ == NULL); }
69 void AddTraceChunkOnFileThread(
70 const scoped_refptr<base::RefCountedString> chunk) {
71 if (file_ != NULL)
72 fputc(',', file_);
73 else if (!OpenFileIfNeededOnFileThread())
74 return;
75 ignore_result(fwrite(chunk->data().c_str(), strlen(chunk->data().c_str()),
76 1, file_));
79 bool OpenFileIfNeededOnFileThread() {
80 if (file_ != NULL)
81 return true;
82 file_ = base::OpenFile(file_path_, "w");
83 if (file_ == NULL) {
84 LOG(ERROR) << "Failed to open " << file_path_.value();
85 return false;
87 const char preamble[] = "{\"traceEvents\": [";
88 ignore_result(fwrite(preamble, strlen(preamble), 1, file_));
89 return true;
92 void CloseOnFileThread() {
93 if (OpenFileIfNeededOnFileThread()) {
94 fputc(']', file_);
95 if (!system_trace_.empty()) {
96 const char systemTraceEvents[] = ",\"systemTraceEvents\": ";
97 ignore_result(fwrite(systemTraceEvents, strlen(systemTraceEvents),
98 1, file_));
99 ignore_result(fwrite(system_trace_.c_str(),
100 strlen(system_trace_.c_str()), 1, file_));
102 fputc('}', file_);
103 base::CloseFile(file_);
104 file_ = NULL;
106 BrowserThread::PostTask(
107 BrowserThread::UI,
108 FROM_HERE,
109 base::Bind(&FileTraceDataSink::FinalizeOnUIThread, this));
112 void FinalizeOnUIThread() { completion_callback_.Run(); }
114 base::FilePath file_path_;
115 base::Closure completion_callback_;
116 FILE* file_;
117 std::string system_trace_;
119 DISALLOW_COPY_AND_ASSIGN(FileTraceDataSink);
122 class StringTraceDataSink : public TracingController::TraceDataSink {
123 public:
124 typedef base::Callback<void(base::RefCountedString*)> CompletionCallback;
126 explicit StringTraceDataSink(CompletionCallback callback)
127 : completion_callback_(callback) {}
129 // TracingController::TraceDataSink implementation
130 void AddTraceChunk(const std::string& chunk) override {
131 if (!trace_.empty())
132 trace_ += ",";
133 trace_ += chunk;
135 void SetSystemTrace(const std::string& data) override {
136 system_trace_ = data;
138 void Close() override {
139 std::string result = "{\"traceEvents\":[" + trace_ + "]";
140 if (!system_trace_.empty())
141 result += ",\"systemTraceEvents\": " + system_trace_;
142 result += "}";
144 scoped_refptr<base::RefCountedString> str =
145 base::RefCountedString::TakeString(&result);
146 completion_callback_.Run(str.get());
149 private:
150 ~StringTraceDataSink() override {}
152 std::string trace_;
153 std::string system_trace_;
154 CompletionCallback completion_callback_;
156 DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink);
159 } // namespace
161 TracingController* TracingController::GetInstance() {
162 return TracingControllerImpl::GetInstance();
165 TracingControllerImpl::TracingControllerImpl()
166 : pending_disable_recording_ack_count_(0),
167 pending_capture_monitoring_snapshot_ack_count_(0),
168 pending_trace_log_status_ack_count_(0),
169 maximum_trace_buffer_usage_(0),
170 approximate_event_count_(0),
171 pending_memory_dump_ack_count_(0),
172 failed_memory_dump_count_(0),
173 // Tracing may have been enabled by ContentMainRunner if kTraceStartup
174 // is specified in command line.
175 #if defined(OS_CHROMEOS) || defined(OS_WIN)
176 is_system_tracing_(false),
177 #endif
178 is_recording_(TraceLog::GetInstance()->IsEnabled()),
179 is_monitoring_(false) {
180 base::trace_event::MemoryDumpManager::GetInstance()->SetDelegate(this);
183 TracingControllerImpl::~TracingControllerImpl() {
184 // This is a Leaky instance.
185 NOTREACHED();
188 TracingControllerImpl* TracingControllerImpl::GetInstance() {
189 return g_controller.Pointer();
192 bool TracingControllerImpl::GetCategories(
193 const GetCategoriesDoneCallback& callback) {
194 DCHECK_CURRENTLY_ON(BrowserThread::UI);
196 // Known categories come back from child processes with the EndTracingAck
197 // message. So to get known categories, just begin and end tracing immediately
198 // afterwards. This will ping all the child processes for categories.
199 pending_get_categories_done_callback_ = callback;
200 if (!EnableRecording(
201 CategoryFilter("*"), TraceOptions(), EnableRecordingDoneCallback())) {
202 pending_get_categories_done_callback_.Reset();
203 return false;
206 bool ok = DisableRecording(NULL);
207 DCHECK(ok);
208 return true;
211 void TracingControllerImpl::SetEnabledOnFileThread(
212 const CategoryFilter& category_filter,
213 int mode,
214 const TraceOptions& trace_options,
215 const base::Closure& callback) {
216 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
218 TraceLog::GetInstance()->SetEnabled(
219 category_filter, static_cast<TraceLog::Mode>(mode), trace_options);
220 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
223 void TracingControllerImpl::SetDisabledOnFileThread(
224 const base::Closure& callback) {
225 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
227 TraceLog::GetInstance()->SetDisabled();
228 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
231 bool TracingControllerImpl::EnableRecording(
232 const CategoryFilter& category_filter,
233 const TraceOptions& trace_options,
234 const EnableRecordingDoneCallback& callback) {
235 DCHECK_CURRENTLY_ON(BrowserThread::UI);
237 if (!can_enable_recording())
238 return false;
239 is_recording_ = true;
241 #if defined(OS_ANDROID)
242 if (pending_get_categories_done_callback_.is_null())
243 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
244 #endif
246 trace_options_ = trace_options;
248 if (trace_options.enable_systrace) {
249 #if defined(OS_CHROMEOS)
250 DCHECK(!is_system_tracing_);
251 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
252 StartSystemTracing();
253 is_system_tracing_ = true;
254 #elif defined(OS_WIN)
255 DCHECK(!is_system_tracing_);
256 is_system_tracing_ =
257 EtwSystemEventConsumer::GetInstance()->StartSystemTracing();
258 #endif
262 base::Closure on_enable_recording_done_callback =
263 base::Bind(&TracingControllerImpl::OnEnableRecordingDone,
264 base::Unretained(this),
265 category_filter, trace_options, callback);
266 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
267 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
268 base::Unretained(this),
269 category_filter,
270 base::trace_event::TraceLog::RECORDING_MODE,
271 trace_options,
272 on_enable_recording_done_callback));
273 return true;
276 void TracingControllerImpl::OnEnableRecordingDone(
277 const CategoryFilter& category_filter,
278 const TraceOptions& trace_options,
279 const EnableRecordingDoneCallback& callback) {
280 DCHECK_CURRENTLY_ON(BrowserThread::UI);
282 // Notify all child processes.
283 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
284 it != trace_message_filters_.end(); ++it) {
285 it->get()->SendBeginTracing(category_filter, trace_options);
288 if (!callback.is_null())
289 callback.Run();
292 bool TracingControllerImpl::DisableRecording(
293 const scoped_refptr<TraceDataSink>& trace_data_sink) {
294 DCHECK_CURRENTLY_ON(BrowserThread::UI);
296 if (!can_disable_recording())
297 return false;
299 trace_data_sink_ = trace_data_sink;
300 trace_options_ = TraceOptions();
301 // Disable local trace early to avoid traces during end-tracing process from
302 // interfering with the process.
303 base::Closure on_disable_recording_done_callback = base::Bind(
304 &TracingControllerImpl::OnDisableRecordingDone, base::Unretained(this));
305 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
306 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
307 base::Unretained(this),
308 on_disable_recording_done_callback));
309 return true;
312 void TracingControllerImpl::OnDisableRecordingDone() {
313 DCHECK_CURRENTLY_ON(BrowserThread::UI);
315 #if defined(OS_ANDROID)
316 if (pending_get_categories_done_callback_.is_null())
317 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
318 #endif
320 // Count myself (local trace) in pending_disable_recording_ack_count_,
321 // acked below.
322 pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
323 pending_disable_recording_filters_ = trace_message_filters_;
325 #if defined(OS_CHROMEOS) || defined(OS_WIN)
326 if (is_system_tracing_) {
327 // Disable system tracing.
328 is_system_tracing_ = false;
329 ++pending_disable_recording_ack_count_;
331 #if defined(OS_CHROMEOS)
332 scoped_refptr<base::TaskRunner> task_runner =
333 BrowserThread::GetBlockingPool();
334 chromeos::DBusThreadManager::Get()
335 ->GetDebugDaemonClient()
336 ->RequestStopSystemTracing(
337 task_runner,
338 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
339 base::Unretained(this)));
340 #elif defined(OS_WIN)
341 EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
342 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
343 base::Unretained(this)));
344 #endif
346 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
348 // Handle special case of zero child processes by immediately flushing the
349 // trace log. Once the flush has completed the caller will be notified that
350 // tracing has ended.
351 if (pending_disable_recording_ack_count_ == 1) {
352 // Flush asynchronously now, because we don't have any children to wait for.
353 TraceLog::GetInstance()->Flush(
354 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
355 base::Unretained(this)),
356 true);
359 // Notify all child processes.
360 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
361 it != trace_message_filters_.end(); ++it) {
362 it->get()->SendEndTracing();
366 bool TracingControllerImpl::EnableMonitoring(
367 const CategoryFilter& category_filter,
368 const TraceOptions& trace_options,
369 const EnableMonitoringDoneCallback& callback) {
370 DCHECK_CURRENTLY_ON(BrowserThread::UI);
372 if (!can_enable_monitoring())
373 return false;
374 OnMonitoringStateChanged(true);
376 #if defined(OS_ANDROID)
377 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
378 #endif
380 trace_options_ = trace_options;
382 base::Closure on_enable_monitoring_done_callback =
383 base::Bind(&TracingControllerImpl::OnEnableMonitoringDone,
384 base::Unretained(this),
385 category_filter, trace_options, callback);
386 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
387 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
388 base::Unretained(this),
389 category_filter,
390 base::trace_event::TraceLog::MONITORING_MODE,
391 trace_options,
392 on_enable_monitoring_done_callback));
393 return true;
396 void TracingControllerImpl::OnEnableMonitoringDone(
397 const CategoryFilter& category_filter,
398 const TraceOptions& trace_options,
399 const EnableMonitoringDoneCallback& callback) {
400 DCHECK_CURRENTLY_ON(BrowserThread::UI);
402 // Notify all child processes.
403 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
404 it != trace_message_filters_.end(); ++it) {
405 it->get()->SendEnableMonitoring(category_filter, trace_options);
408 if (!callback.is_null())
409 callback.Run();
412 bool TracingControllerImpl::DisableMonitoring(
413 const DisableMonitoringDoneCallback& callback) {
414 DCHECK_CURRENTLY_ON(BrowserThread::UI);
416 if (!can_disable_monitoring())
417 return false;
419 trace_options_ = TraceOptions();
420 base::Closure on_disable_monitoring_done_callback =
421 base::Bind(&TracingControllerImpl::OnDisableMonitoringDone,
422 base::Unretained(this), callback);
423 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
424 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
425 base::Unretained(this),
426 on_disable_monitoring_done_callback));
427 return true;
430 scoped_refptr<TracingController::TraceDataSink>
431 TracingController::CreateStringSink(
432 const base::Callback<void(base::RefCountedString*)>& callback) {
433 return new StringTraceDataSink(callback);
436 scoped_refptr<TracingController::TraceDataSink>
437 TracingController::CreateFileSink(const base::FilePath& file_path,
438 const base::Closure& callback) {
439 return new FileTraceDataSink(file_path, callback);
442 void TracingControllerImpl::OnDisableMonitoringDone(
443 const DisableMonitoringDoneCallback& callback) {
444 DCHECK_CURRENTLY_ON(BrowserThread::UI);
446 OnMonitoringStateChanged(false);
448 // Notify all child processes.
449 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
450 it != trace_message_filters_.end(); ++it) {
451 it->get()->SendDisableMonitoring();
453 if (!callback.is_null())
454 callback.Run();
457 void TracingControllerImpl::GetMonitoringStatus(
458 bool* out_enabled,
459 CategoryFilter* out_category_filter,
460 TraceOptions* out_trace_options) {
461 *out_enabled = is_monitoring_;
462 *out_category_filter = TraceLog::GetInstance()->GetCurrentCategoryFilter();
463 *out_trace_options = trace_options_;
466 bool TracingControllerImpl::CaptureMonitoringSnapshot(
467 const scoped_refptr<TraceDataSink>& monitoring_data_sink) {
468 DCHECK_CURRENTLY_ON(BrowserThread::UI);
470 if (!can_disable_monitoring())
471 return false;
473 if (!monitoring_data_sink.get())
474 return false;
476 monitoring_data_sink_ = monitoring_data_sink;
478 // Count myself in pending_capture_monitoring_snapshot_ack_count_,
479 // acked below.
480 pending_capture_monitoring_snapshot_ack_count_ =
481 trace_message_filters_.size() + 1;
482 pending_capture_monitoring_filters_ = trace_message_filters_;
484 // Handle special case of zero child processes by immediately flushing the
485 // trace log. Once the flush has completed the caller will be notified that
486 // the capture snapshot has ended.
487 if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
488 // Flush asynchronously now, because we don't have any children to wait for.
489 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
490 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
491 base::Unretained(this)));
494 // Notify all child processes.
495 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
496 it != trace_message_filters_.end(); ++it) {
497 it->get()->SendCaptureMonitoringSnapshot();
500 #if defined(OS_ANDROID)
501 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
502 #endif
504 return true;
507 bool TracingControllerImpl::GetTraceBufferUsage(
508 const GetTraceBufferUsageCallback& callback) {
509 DCHECK_CURRENTLY_ON(BrowserThread::UI);
511 if (!can_get_trace_buffer_usage() || callback.is_null())
512 return false;
514 pending_trace_buffer_usage_callback_ = callback;
516 // Count myself in pending_trace_log_status_ack_count_, acked below.
517 pending_trace_log_status_ack_count_ = trace_message_filters_.size() + 1;
518 pending_trace_log_status_filters_ = trace_message_filters_;
519 maximum_trace_buffer_usage_ = 0;
520 approximate_event_count_ = 0;
522 base::trace_event::TraceLogStatus status =
523 TraceLog::GetInstance()->GetStatus();
524 // Call OnTraceLogStatusReply unconditionally for the browser process.
525 // This will result in immediate execution of the callback if there are no
526 // child processes.
527 BrowserThread::PostTask(
528 BrowserThread::UI, FROM_HERE,
529 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
530 base::Unretained(this), scoped_refptr<TraceMessageFilter>(),
531 status));
533 // Notify all child processes.
534 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
535 it != trace_message_filters_.end(); ++it) {
536 it->get()->SendGetTraceLogStatus();
538 return true;
541 bool TracingControllerImpl::SetWatchEvent(
542 const std::string& category_name,
543 const std::string& event_name,
544 const WatchEventCallback& callback) {
545 DCHECK_CURRENTLY_ON(BrowserThread::UI);
547 if (callback.is_null())
548 return false;
550 watch_category_name_ = category_name;
551 watch_event_name_ = event_name;
552 watch_event_callback_ = callback;
554 TraceLog::GetInstance()->SetWatchEvent(
555 category_name, event_name,
556 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
557 base::Unretained(this)));
559 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
560 it != trace_message_filters_.end(); ++it) {
561 it->get()->SendSetWatchEvent(category_name, event_name);
563 return true;
566 bool TracingControllerImpl::CancelWatchEvent() {
567 DCHECK_CURRENTLY_ON(BrowserThread::UI);
569 if (!can_cancel_watch_event())
570 return false;
572 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
573 it != trace_message_filters_.end(); ++it) {
574 it->get()->SendCancelWatchEvent();
577 watch_event_callback_.Reset();
578 return true;
581 void TracingControllerImpl::AddTraceMessageFilter(
582 TraceMessageFilter* trace_message_filter) {
583 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
584 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
585 base::Bind(&TracingControllerImpl::AddTraceMessageFilter,
586 base::Unretained(this),
587 make_scoped_refptr(trace_message_filter)));
588 return;
591 trace_message_filters_.insert(trace_message_filter);
592 if (can_cancel_watch_event()) {
593 trace_message_filter->SendSetWatchEvent(watch_category_name_,
594 watch_event_name_);
596 if (can_disable_recording()) {
597 trace_message_filter->SendBeginTracing(
598 TraceLog::GetInstance()->GetCurrentCategoryFilter(),
599 TraceLog::GetInstance()->GetCurrentTraceOptions());
601 if (can_disable_monitoring()) {
602 trace_message_filter->SendEnableMonitoring(
603 TraceLog::GetInstance()->GetCurrentCategoryFilter(),
604 TraceLog::GetInstance()->GetCurrentTraceOptions());
608 void TracingControllerImpl::RemoveTraceMessageFilter(
609 TraceMessageFilter* trace_message_filter) {
610 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
611 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
612 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter,
613 base::Unretained(this),
614 make_scoped_refptr(trace_message_filter)));
615 return;
618 // If a filter is removed while a response from that filter is pending then
619 // simulate the response. Otherwise the response count will be wrong and the
620 // completion callback will never be executed.
621 if (pending_disable_recording_ack_count_ > 0) {
622 TraceMessageFilterSet::const_iterator it =
623 pending_disable_recording_filters_.find(trace_message_filter);
624 if (it != pending_disable_recording_filters_.end()) {
625 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
626 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
627 base::Unretained(this),
628 make_scoped_refptr(trace_message_filter),
629 std::vector<std::string>()));
632 if (pending_capture_monitoring_snapshot_ack_count_ > 0) {
633 TraceMessageFilterSet::const_iterator it =
634 pending_capture_monitoring_filters_.find(trace_message_filter);
635 if (it != pending_capture_monitoring_filters_.end()) {
636 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
637 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
638 base::Unretained(this),
639 make_scoped_refptr(trace_message_filter)));
642 if (pending_trace_log_status_ack_count_ > 0) {
643 TraceMessageFilterSet::const_iterator it =
644 pending_trace_log_status_filters_.find(trace_message_filter);
645 if (it != pending_trace_log_status_filters_.end()) {
646 BrowserThread::PostTask(
647 BrowserThread::UI, FROM_HERE,
648 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
649 base::Unretained(this),
650 make_scoped_refptr(trace_message_filter),
651 base::trace_event::TraceLogStatus()));
654 if (pending_memory_dump_ack_count_ > 0) {
655 TraceMessageFilterSet::const_iterator it =
656 pending_memory_dump_filters_.find(trace_message_filter);
657 if (it != pending_memory_dump_filters_.end()) {
658 BrowserThread::PostTask(
659 BrowserThread::UI, FROM_HERE,
660 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
661 base::Unretained(this),
662 make_scoped_refptr(trace_message_filter),
663 pending_memory_dump_guid_, false /* success */));
666 trace_message_filters_.erase(trace_message_filter);
669 void TracingControllerImpl::OnDisableRecordingAcked(
670 TraceMessageFilter* trace_message_filter,
671 const std::vector<std::string>& known_category_groups) {
672 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
673 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
674 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
675 base::Unretained(this),
676 make_scoped_refptr(trace_message_filter),
677 known_category_groups));
678 return;
681 // Merge known_category_groups with known_category_groups_
682 known_category_groups_.insert(known_category_groups.begin(),
683 known_category_groups.end());
685 if (pending_disable_recording_ack_count_ == 0)
686 return;
688 if (trace_message_filter &&
689 !pending_disable_recording_filters_.erase(trace_message_filter)) {
690 // The response from the specified message filter has already been received.
691 return;
694 if (--pending_disable_recording_ack_count_ == 1) {
695 // All acks from subprocesses have been received. Now flush the local trace.
696 // During or after this call, our OnLocalTraceDataCollected will be
697 // called with the last of the local trace data.
698 TraceLog::GetInstance()->Flush(
699 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
700 base::Unretained(this)),
701 true);
702 return;
705 if (pending_disable_recording_ack_count_ != 0)
706 return;
708 // All acks (including from the subprocesses and the local trace) have been
709 // received.
710 is_recording_ = false;
712 // Trigger callback if one is set.
713 if (!pending_get_categories_done_callback_.is_null()) {
714 pending_get_categories_done_callback_.Run(known_category_groups_);
715 pending_get_categories_done_callback_.Reset();
716 } else if (trace_data_sink_.get()) {
717 trace_data_sink_->Close();
718 trace_data_sink_ = NULL;
722 #if defined(OS_CHROMEOS) || defined(OS_WIN)
723 void TracingControllerImpl::OnEndSystemTracingAcked(
724 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
725 DCHECK_CURRENTLY_ON(BrowserThread::UI);
727 if (trace_data_sink_.get()) {
728 #if defined(OS_WIN)
729 // The Windows kernel events are kept into a JSon format stored as string
730 // and must not be escaped.
731 std::string json_string = events_str_ptr->data();
732 #else
733 std::string json_string =
734 base::GetQuotedJSONString(events_str_ptr->data());
735 #endif
736 trace_data_sink_->SetSystemTrace(json_string);
738 DCHECK(!is_system_tracing_);
739 std::vector<std::string> category_groups;
740 OnDisableRecordingAcked(NULL, category_groups);
742 #endif
744 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
745 TraceMessageFilter* trace_message_filter) {
746 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
747 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
748 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
749 base::Unretained(this),
750 make_scoped_refptr(trace_message_filter)));
751 return;
754 if (pending_capture_monitoring_snapshot_ack_count_ == 0)
755 return;
757 if (trace_message_filter &&
758 !pending_capture_monitoring_filters_.erase(trace_message_filter)) {
759 // The response from the specified message filter has already been received.
760 return;
763 if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
764 // All acks from subprocesses have been received. Now flush the local trace.
765 // During or after this call, our OnLocalMonitoringTraceDataCollected
766 // will be called with the last of the local trace data.
767 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
768 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
769 base::Unretained(this)));
770 return;
773 if (pending_capture_monitoring_snapshot_ack_count_ != 0)
774 return;
776 if (monitoring_data_sink_.get()) {
777 monitoring_data_sink_->Close();
778 monitoring_data_sink_ = NULL;
782 void TracingControllerImpl::OnTraceDataCollected(
783 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
784 // OnTraceDataCollected may be called from any browser thread, either by the
785 // local event trace system or from child processes via TraceMessageFilter.
786 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
787 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
788 base::Bind(&TracingControllerImpl::OnTraceDataCollected,
789 base::Unretained(this), events_str_ptr));
790 return;
793 if (trace_data_sink_.get())
794 trace_data_sink_->AddTraceChunk(events_str_ptr->data());
797 void TracingControllerImpl::OnMonitoringTraceDataCollected(
798 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
799 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
800 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
801 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
802 base::Unretained(this), events_str_ptr));
803 return;
806 if (monitoring_data_sink_.get())
807 monitoring_data_sink_->AddTraceChunk(events_str_ptr->data());
810 void TracingControllerImpl::OnLocalTraceDataCollected(
811 const scoped_refptr<base::RefCountedString>& events_str_ptr,
812 bool has_more_events) {
813 if (events_str_ptr->data().size())
814 OnTraceDataCollected(events_str_ptr);
816 if (has_more_events)
817 return;
819 // Simulate an DisableRecordingAcked for the local trace.
820 std::vector<std::string> category_groups;
821 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
822 OnDisableRecordingAcked(NULL, category_groups);
825 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
826 const scoped_refptr<base::RefCountedString>& events_str_ptr,
827 bool has_more_events) {
828 if (events_str_ptr->data().size())
829 OnMonitoringTraceDataCollected(events_str_ptr);
831 if (has_more_events)
832 return;
834 // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
835 OnCaptureMonitoringSnapshotAcked(NULL);
838 void TracingControllerImpl::OnTraceLogStatusReply(
839 TraceMessageFilter* trace_message_filter,
840 const base::trace_event::TraceLogStatus& status) {
841 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
842 BrowserThread::PostTask(
843 BrowserThread::UI, FROM_HERE,
844 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
845 base::Unretained(this),
846 make_scoped_refptr(trace_message_filter), status));
847 return;
850 if (pending_trace_log_status_ack_count_ == 0)
851 return;
853 if (trace_message_filter &&
854 !pending_trace_log_status_filters_.erase(trace_message_filter)) {
855 // The response from the specified message filter has already been received.
856 return;
859 float percent_full = static_cast<float>(
860 static_cast<double>(status.event_count) / status.event_capacity);
861 maximum_trace_buffer_usage_ =
862 std::max(maximum_trace_buffer_usage_, percent_full);
863 approximate_event_count_ += status.event_count;
865 if (--pending_trace_log_status_ack_count_ == 0) {
866 // Trigger callback if one is set.
867 pending_trace_buffer_usage_callback_.Run(maximum_trace_buffer_usage_,
868 approximate_event_count_);
869 pending_trace_buffer_usage_callback_.Reset();
873 void TracingControllerImpl::OnWatchEventMatched() {
874 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
875 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
876 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
877 base::Unretained(this)));
878 return;
881 if (!watch_event_callback_.is_null())
882 watch_event_callback_.Run();
885 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) {
886 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end());
887 tracing_uis_.insert(tracing_ui);
890 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) {
891 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui);
892 DCHECK(it != tracing_uis_.end());
893 tracing_uis_.erase(it);
896 void TracingControllerImpl::RequestGlobalMemoryDump(
897 const base::trace_event::MemoryDumpRequestArgs& args,
898 const base::trace_event::MemoryDumpCallback& callback) {
899 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
900 BrowserThread::PostTask(
901 BrowserThread::UI, FROM_HERE,
902 base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump,
903 base::Unretained(this), args, callback));
904 return;
906 // Abort if another dump is already in progress.
907 if (pending_memory_dump_guid_) {
908 DVLOG(1) << "Requested memory dump " << args.dump_guid
909 << " while waiting for " << pending_memory_dump_guid_;
910 if (!callback.is_null())
911 callback.Run(args.dump_guid, false /* success */);
912 return;
915 // Count myself (local trace) in pending_memory_dump_ack_count_, acked by
916 // OnBrowserProcessMemoryDumpDone().
917 pending_memory_dump_ack_count_ = trace_message_filters_.size() + 1;
918 pending_memory_dump_filters_.clear();
919 failed_memory_dump_count_ = 0;
921 MemoryDumpManagerDelegate::CreateProcessDump(
922 args, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone,
923 base::Unretained(this)));
925 // If there are no child processes we are just done.
926 if (pending_memory_dump_ack_count_ == 1) {
927 if (!callback.is_null())
928 callback.Run(args.dump_guid, true /* success */);
929 return;
932 pending_memory_dump_guid_ = args.dump_guid;
933 pending_memory_dump_callback_ = callback;
934 pending_memory_dump_filters_ = trace_message_filters_;
936 for (const scoped_refptr<TraceMessageFilter>& tmf : trace_message_filters_)
937 tmf->SendProcessMemoryDumpRequest(args);
940 bool TracingControllerImpl::IsCoordinatorProcess() const {
941 return true;
944 void TracingControllerImpl::OnProcessMemoryDumpResponse(
945 TraceMessageFilter* trace_message_filter,
946 uint64 dump_guid,
947 bool success) {
948 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
949 BrowserThread::PostTask(
950 BrowserThread::UI, FROM_HERE,
951 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
952 base::Unretained(this),
953 make_scoped_refptr(trace_message_filter), dump_guid,
954 success));
955 return;
958 TraceMessageFilterSet::iterator it =
959 pending_memory_dump_filters_.find(trace_message_filter);
961 if (pending_memory_dump_guid_ != dump_guid ||
962 it == pending_memory_dump_filters_.end()) {
963 DLOG(WARNING) << "Received unexpected memory dump response: " << dump_guid;
964 return;
967 DCHECK_GT(pending_memory_dump_ack_count_, 0);
968 --pending_memory_dump_ack_count_;
969 pending_memory_dump_filters_.erase(it);
970 if (!success) {
971 ++failed_memory_dump_count_;
972 DLOG(WARNING) << "Global memory dump failed because of NACK from child "
973 << trace_message_filter->peer_pid();
975 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
978 void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64 dump_guid,
979 bool success) {
980 DCHECK_GT(pending_memory_dump_ack_count_, 0);
981 --pending_memory_dump_ack_count_;
982 FinalizeGlobalMemoryDumpIfAllProcessesReplied();
985 void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() {
986 if (pending_memory_dump_ack_count_ > 0)
987 return;
989 DCHECK_NE(0u, pending_memory_dump_guid_);
990 const bool global_success = failed_memory_dump_count_ == 0;
991 if (!pending_memory_dump_callback_.is_null()) {
992 pending_memory_dump_callback_.Run(pending_memory_dump_guid_,
993 global_success);
994 pending_memory_dump_callback_.Reset();
996 pending_memory_dump_guid_ = 0;
999 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
1000 if (is_monitoring_ == is_monitoring)
1001 return;
1003 is_monitoring_ = is_monitoring;
1004 #if !defined(OS_ANDROID)
1005 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin();
1006 it != tracing_uis_.end(); it++) {
1007 (*it)->OnMonitoringStateChanged(is_monitoring);
1009 #endif
1012 } // namespace content