Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / tracing / tracing_controller_impl.cc
blob869946fb510631304e94c1a11fdf1c9ddb5afa9f
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 // Tracing may have been enabled by ContentMainRunner if kTraceStartup
172 // is specified in command line.
173 #if defined(OS_CHROMEOS) || defined(OS_WIN)
174 is_system_tracing_(false),
175 #endif
176 is_recording_(TraceLog::GetInstance()->IsEnabled()),
177 is_monitoring_(false) {
178 base::trace_event::MemoryDumpManager::GetInstance()->SetDelegate(this);
181 TracingControllerImpl::~TracingControllerImpl() {
182 // This is a Leaky instance.
183 NOTREACHED();
186 TracingControllerImpl* TracingControllerImpl::GetInstance() {
187 return g_controller.Pointer();
190 bool TracingControllerImpl::GetCategories(
191 const GetCategoriesDoneCallback& callback) {
192 DCHECK_CURRENTLY_ON(BrowserThread::UI);
194 // Known categories come back from child processes with the EndTracingAck
195 // message. So to get known categories, just begin and end tracing immediately
196 // afterwards. This will ping all the child processes for categories.
197 pending_get_categories_done_callback_ = callback;
198 if (!EnableRecording(
199 CategoryFilter("*"), TraceOptions(), EnableRecordingDoneCallback())) {
200 pending_get_categories_done_callback_.Reset();
201 return false;
204 bool ok = DisableRecording(NULL);
205 DCHECK(ok);
206 return true;
209 void TracingControllerImpl::SetEnabledOnFileThread(
210 const CategoryFilter& category_filter,
211 int mode,
212 const TraceOptions& trace_options,
213 const base::Closure& callback) {
214 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
216 TraceLog::GetInstance()->SetEnabled(
217 category_filter, static_cast<TraceLog::Mode>(mode), trace_options);
218 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
221 void TracingControllerImpl::SetDisabledOnFileThread(
222 const base::Closure& callback) {
223 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
225 TraceLog::GetInstance()->SetDisabled();
226 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
229 bool TracingControllerImpl::EnableRecording(
230 const CategoryFilter& category_filter,
231 const TraceOptions& trace_options,
232 const EnableRecordingDoneCallback& callback) {
233 DCHECK_CURRENTLY_ON(BrowserThread::UI);
235 if (!can_enable_recording())
236 return false;
237 is_recording_ = true;
239 #if defined(OS_ANDROID)
240 if (pending_get_categories_done_callback_.is_null())
241 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
242 #endif
244 trace_options_ = trace_options;
246 if (trace_options.enable_systrace) {
247 #if defined(OS_CHROMEOS)
248 DCHECK(!is_system_tracing_);
249 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
250 StartSystemTracing();
251 is_system_tracing_ = true;
252 #elif defined(OS_WIN)
253 DCHECK(!is_system_tracing_);
254 is_system_tracing_ =
255 EtwSystemEventConsumer::GetInstance()->StartSystemTracing();
256 #endif
260 base::Closure on_enable_recording_done_callback =
261 base::Bind(&TracingControllerImpl::OnEnableRecordingDone,
262 base::Unretained(this),
263 category_filter, trace_options, callback);
264 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
265 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
266 base::Unretained(this),
267 category_filter,
268 base::trace_event::TraceLog::RECORDING_MODE,
269 trace_options,
270 on_enable_recording_done_callback));
271 return true;
274 void TracingControllerImpl::OnEnableRecordingDone(
275 const CategoryFilter& category_filter,
276 const TraceOptions& trace_options,
277 const EnableRecordingDoneCallback& callback) {
278 DCHECK_CURRENTLY_ON(BrowserThread::UI);
280 // Notify all child processes.
281 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
282 it != trace_message_filters_.end(); ++it) {
283 it->get()->SendBeginTracing(category_filter, trace_options);
286 if (!callback.is_null())
287 callback.Run();
290 bool TracingControllerImpl::DisableRecording(
291 const scoped_refptr<TraceDataSink>& trace_data_sink) {
292 DCHECK_CURRENTLY_ON(BrowserThread::UI);
294 if (!can_disable_recording())
295 return false;
297 trace_data_sink_ = trace_data_sink;
298 trace_options_ = TraceOptions();
299 // Disable local trace early to avoid traces during end-tracing process from
300 // interfering with the process.
301 base::Closure on_disable_recording_done_callback = base::Bind(
302 &TracingControllerImpl::OnDisableRecordingDone, base::Unretained(this));
303 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
304 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
305 base::Unretained(this),
306 on_disable_recording_done_callback));
307 return true;
310 void TracingControllerImpl::OnDisableRecordingDone() {
311 DCHECK_CURRENTLY_ON(BrowserThread::UI);
313 #if defined(OS_ANDROID)
314 if (pending_get_categories_done_callback_.is_null())
315 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
316 #endif
318 // Count myself (local trace) in pending_disable_recording_ack_count_,
319 // acked below.
320 pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
321 pending_disable_recording_filters_ = trace_message_filters_;
323 #if defined(OS_CHROMEOS) || defined(OS_WIN)
324 if (is_system_tracing_) {
325 // Disable system tracing.
326 is_system_tracing_ = false;
327 ++pending_disable_recording_ack_count_;
329 #if defined(OS_CHROMEOS)
330 scoped_refptr<base::TaskRunner> task_runner =
331 BrowserThread::GetBlockingPool();
332 chromeos::DBusThreadManager::Get()
333 ->GetDebugDaemonClient()
334 ->RequestStopSystemTracing(
335 task_runner,
336 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
337 base::Unretained(this)));
338 #elif defined(OS_WIN)
339 EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
340 base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
341 base::Unretained(this)));
342 #endif
344 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
346 // Handle special case of zero child processes by immediately flushing the
347 // trace log. Once the flush has completed the caller will be notified that
348 // tracing has ended.
349 if (pending_disable_recording_ack_count_ == 1) {
350 // Flush asynchronously now, because we don't have any children to wait for.
351 TraceLog::GetInstance()->Flush(
352 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
353 base::Unretained(this)),
354 true);
357 // Notify all child processes.
358 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
359 it != trace_message_filters_.end(); ++it) {
360 it->get()->SendEndTracing();
364 bool TracingControllerImpl::EnableMonitoring(
365 const CategoryFilter& category_filter,
366 const TraceOptions& trace_options,
367 const EnableMonitoringDoneCallback& callback) {
368 DCHECK_CURRENTLY_ON(BrowserThread::UI);
370 if (!can_enable_monitoring())
371 return false;
372 OnMonitoringStateChanged(true);
374 #if defined(OS_ANDROID)
375 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
376 #endif
378 trace_options_ = trace_options;
380 base::Closure on_enable_monitoring_done_callback =
381 base::Bind(&TracingControllerImpl::OnEnableMonitoringDone,
382 base::Unretained(this),
383 category_filter, trace_options, callback);
384 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
385 base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
386 base::Unretained(this),
387 category_filter,
388 base::trace_event::TraceLog::MONITORING_MODE,
389 trace_options,
390 on_enable_monitoring_done_callback));
391 return true;
394 void TracingControllerImpl::OnEnableMonitoringDone(
395 const CategoryFilter& category_filter,
396 const TraceOptions& trace_options,
397 const EnableMonitoringDoneCallback& callback) {
398 DCHECK_CURRENTLY_ON(BrowserThread::UI);
400 // Notify all child processes.
401 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
402 it != trace_message_filters_.end(); ++it) {
403 it->get()->SendEnableMonitoring(category_filter, trace_options);
406 if (!callback.is_null())
407 callback.Run();
410 bool TracingControllerImpl::DisableMonitoring(
411 const DisableMonitoringDoneCallback& callback) {
412 DCHECK_CURRENTLY_ON(BrowserThread::UI);
414 if (!can_disable_monitoring())
415 return false;
417 trace_options_ = TraceOptions();
418 base::Closure on_disable_monitoring_done_callback =
419 base::Bind(&TracingControllerImpl::OnDisableMonitoringDone,
420 base::Unretained(this), callback);
421 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
422 base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
423 base::Unretained(this),
424 on_disable_monitoring_done_callback));
425 return true;
428 scoped_refptr<TracingController::TraceDataSink>
429 TracingController::CreateStringSink(
430 const base::Callback<void(base::RefCountedString*)>& callback) {
431 return new StringTraceDataSink(callback);
434 scoped_refptr<TracingController::TraceDataSink>
435 TracingController::CreateFileSink(const base::FilePath& file_path,
436 const base::Closure& callback) {
437 return new FileTraceDataSink(file_path, callback);
440 void TracingControllerImpl::OnDisableMonitoringDone(
441 const DisableMonitoringDoneCallback& callback) {
442 DCHECK_CURRENTLY_ON(BrowserThread::UI);
444 OnMonitoringStateChanged(false);
446 // Notify all child processes.
447 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
448 it != trace_message_filters_.end(); ++it) {
449 it->get()->SendDisableMonitoring();
451 if (!callback.is_null())
452 callback.Run();
455 void TracingControllerImpl::GetMonitoringStatus(
456 bool* out_enabled,
457 CategoryFilter* out_category_filter,
458 TraceOptions* out_trace_options) {
459 *out_enabled = is_monitoring_;
460 *out_category_filter = TraceLog::GetInstance()->GetCurrentCategoryFilter();
461 *out_trace_options = trace_options_;
464 bool TracingControllerImpl::CaptureMonitoringSnapshot(
465 const scoped_refptr<TraceDataSink>& monitoring_data_sink) {
466 DCHECK_CURRENTLY_ON(BrowserThread::UI);
468 if (!can_disable_monitoring())
469 return false;
471 if (!monitoring_data_sink.get())
472 return false;
474 monitoring_data_sink_ = monitoring_data_sink;
476 // Count myself in pending_capture_monitoring_snapshot_ack_count_,
477 // acked below.
478 pending_capture_monitoring_snapshot_ack_count_ =
479 trace_message_filters_.size() + 1;
480 pending_capture_monitoring_filters_ = trace_message_filters_;
482 // Handle special case of zero child processes by immediately flushing the
483 // trace log. Once the flush has completed the caller will be notified that
484 // the capture snapshot has ended.
485 if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
486 // Flush asynchronously now, because we don't have any children to wait for.
487 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
488 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
489 base::Unretained(this)));
492 // Notify all child processes.
493 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
494 it != trace_message_filters_.end(); ++it) {
495 it->get()->SendCaptureMonitoringSnapshot();
498 #if defined(OS_ANDROID)
499 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
500 #endif
502 return true;
505 bool TracingControllerImpl::GetTraceBufferUsage(
506 const GetTraceBufferUsageCallback& callback) {
507 DCHECK_CURRENTLY_ON(BrowserThread::UI);
509 if (!can_get_trace_buffer_usage() || callback.is_null())
510 return false;
512 pending_trace_buffer_usage_callback_ = callback;
514 // Count myself in pending_trace_log_status_ack_count_, acked below.
515 pending_trace_log_status_ack_count_ = trace_message_filters_.size() + 1;
516 pending_trace_log_status_filters_ = trace_message_filters_;
517 maximum_trace_buffer_usage_ = 0;
518 approximate_event_count_ = 0;
520 base::trace_event::TraceLogStatus status =
521 TraceLog::GetInstance()->GetStatus();
522 // Call OnTraceLogStatusReply unconditionally for the browser process.
523 // This will result in immediate execution of the callback if there are no
524 // child processes.
525 BrowserThread::PostTask(
526 BrowserThread::UI, FROM_HERE,
527 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
528 base::Unretained(this), scoped_refptr<TraceMessageFilter>(),
529 status));
531 // Notify all child processes.
532 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
533 it != trace_message_filters_.end(); ++it) {
534 it->get()->SendGetTraceLogStatus();
536 return true;
539 bool TracingControllerImpl::SetWatchEvent(
540 const std::string& category_name,
541 const std::string& event_name,
542 const WatchEventCallback& callback) {
543 DCHECK_CURRENTLY_ON(BrowserThread::UI);
545 if (callback.is_null())
546 return false;
548 watch_category_name_ = category_name;
549 watch_event_name_ = event_name;
550 watch_event_callback_ = callback;
552 TraceLog::GetInstance()->SetWatchEvent(
553 category_name, event_name,
554 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
555 base::Unretained(this)));
557 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
558 it != trace_message_filters_.end(); ++it) {
559 it->get()->SendSetWatchEvent(category_name, event_name);
561 return true;
564 bool TracingControllerImpl::CancelWatchEvent() {
565 DCHECK_CURRENTLY_ON(BrowserThread::UI);
567 if (!can_cancel_watch_event())
568 return false;
570 for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
571 it != trace_message_filters_.end(); ++it) {
572 it->get()->SendCancelWatchEvent();
575 watch_event_callback_.Reset();
576 return true;
579 void TracingControllerImpl::AddTraceMessageFilter(
580 TraceMessageFilter* trace_message_filter) {
581 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
582 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
583 base::Bind(&TracingControllerImpl::AddTraceMessageFilter,
584 base::Unretained(this),
585 make_scoped_refptr(trace_message_filter)));
586 return;
589 trace_message_filters_.insert(trace_message_filter);
590 if (can_cancel_watch_event()) {
591 trace_message_filter->SendSetWatchEvent(watch_category_name_,
592 watch_event_name_);
594 if (can_disable_recording()) {
595 trace_message_filter->SendBeginTracing(
596 TraceLog::GetInstance()->GetCurrentCategoryFilter(),
597 TraceLog::GetInstance()->GetCurrentTraceOptions());
599 if (can_disable_monitoring()) {
600 trace_message_filter->SendEnableMonitoring(
601 TraceLog::GetInstance()->GetCurrentCategoryFilter(),
602 TraceLog::GetInstance()->GetCurrentTraceOptions());
606 void TracingControllerImpl::RemoveTraceMessageFilter(
607 TraceMessageFilter* trace_message_filter) {
608 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
609 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
610 base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter,
611 base::Unretained(this),
612 make_scoped_refptr(trace_message_filter)));
613 return;
616 // If a filter is removed while a response from that filter is pending then
617 // simulate the response. Otherwise the response count will be wrong and the
618 // completion callback will never be executed.
619 if (pending_disable_recording_ack_count_ > 0) {
620 TraceMessageFilterSet::const_iterator it =
621 pending_disable_recording_filters_.find(trace_message_filter);
622 if (it != pending_disable_recording_filters_.end()) {
623 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
624 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
625 base::Unretained(this),
626 make_scoped_refptr(trace_message_filter),
627 std::vector<std::string>()));
630 if (pending_capture_monitoring_snapshot_ack_count_ > 0) {
631 TraceMessageFilterSet::const_iterator it =
632 pending_capture_monitoring_filters_.find(trace_message_filter);
633 if (it != pending_capture_monitoring_filters_.end()) {
634 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
635 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
636 base::Unretained(this),
637 make_scoped_refptr(trace_message_filter)));
640 if (pending_trace_log_status_ack_count_ > 0) {
641 TraceMessageFilterSet::const_iterator it =
642 pending_trace_log_status_filters_.find(trace_message_filter);
643 if (it != pending_trace_log_status_filters_.end()) {
644 BrowserThread::PostTask(
645 BrowserThread::UI, FROM_HERE,
646 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
647 base::Unretained(this),
648 make_scoped_refptr(trace_message_filter),
649 base::trace_event::TraceLogStatus()));
653 trace_message_filters_.erase(trace_message_filter);
656 void TracingControllerImpl::OnDisableRecordingAcked(
657 TraceMessageFilter* trace_message_filter,
658 const std::vector<std::string>& known_category_groups) {
659 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
660 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
661 base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
662 base::Unretained(this),
663 make_scoped_refptr(trace_message_filter),
664 known_category_groups));
665 return;
668 // Merge known_category_groups with known_category_groups_
669 known_category_groups_.insert(known_category_groups.begin(),
670 known_category_groups.end());
672 if (pending_disable_recording_ack_count_ == 0)
673 return;
675 if (trace_message_filter &&
676 !pending_disable_recording_filters_.erase(trace_message_filter)) {
677 // The response from the specified message filter has already been received.
678 return;
681 if (--pending_disable_recording_ack_count_ == 1) {
682 // All acks from subprocesses have been received. Now flush the local trace.
683 // During or after this call, our OnLocalTraceDataCollected will be
684 // called with the last of the local trace data.
685 TraceLog::GetInstance()->Flush(
686 base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
687 base::Unretained(this)),
688 true);
689 return;
692 if (pending_disable_recording_ack_count_ != 0)
693 return;
695 // All acks (including from the subprocesses and the local trace) have been
696 // received.
697 is_recording_ = false;
699 // Trigger callback if one is set.
700 if (!pending_get_categories_done_callback_.is_null()) {
701 pending_get_categories_done_callback_.Run(known_category_groups_);
702 pending_get_categories_done_callback_.Reset();
703 } else if (trace_data_sink_.get()) {
704 trace_data_sink_->Close();
705 trace_data_sink_ = NULL;
709 #if defined(OS_CHROMEOS) || defined(OS_WIN)
710 void TracingControllerImpl::OnEndSystemTracingAcked(
711 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
712 DCHECK_CURRENTLY_ON(BrowserThread::UI);
714 if (trace_data_sink_.get()) {
715 #if defined(OS_WIN)
716 // The Windows kernel events are kept into a JSon format stored as string
717 // and must not be escaped.
718 std::string json_string = events_str_ptr->data();
719 #else
720 std::string json_string =
721 base::GetQuotedJSONString(events_str_ptr->data());
722 #endif
723 trace_data_sink_->SetSystemTrace(json_string);
725 DCHECK(!is_system_tracing_);
726 std::vector<std::string> category_groups;
727 OnDisableRecordingAcked(NULL, category_groups);
729 #endif
731 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
732 TraceMessageFilter* trace_message_filter) {
733 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
734 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
735 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
736 base::Unretained(this),
737 make_scoped_refptr(trace_message_filter)));
738 return;
741 if (pending_capture_monitoring_snapshot_ack_count_ == 0)
742 return;
744 if (trace_message_filter &&
745 !pending_capture_monitoring_filters_.erase(trace_message_filter)) {
746 // The response from the specified message filter has already been received.
747 return;
750 if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
751 // All acks from subprocesses have been received. Now flush the local trace.
752 // During or after this call, our OnLocalMonitoringTraceDataCollected
753 // will be called with the last of the local trace data.
754 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
755 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
756 base::Unretained(this)));
757 return;
760 if (pending_capture_monitoring_snapshot_ack_count_ != 0)
761 return;
763 if (monitoring_data_sink_.get()) {
764 monitoring_data_sink_->Close();
765 monitoring_data_sink_ = NULL;
769 void TracingControllerImpl::OnTraceDataCollected(
770 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
771 // OnTraceDataCollected may be called from any browser thread, either by the
772 // local event trace system or from child processes via TraceMessageFilter.
773 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
774 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
775 base::Bind(&TracingControllerImpl::OnTraceDataCollected,
776 base::Unretained(this), events_str_ptr));
777 return;
780 if (trace_data_sink_.get())
781 trace_data_sink_->AddTraceChunk(events_str_ptr->data());
784 void TracingControllerImpl::OnMonitoringTraceDataCollected(
785 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
786 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
787 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
788 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
789 base::Unretained(this), events_str_ptr));
790 return;
793 if (monitoring_data_sink_.get())
794 monitoring_data_sink_->AddTraceChunk(events_str_ptr->data());
797 void TracingControllerImpl::OnLocalTraceDataCollected(
798 const scoped_refptr<base::RefCountedString>& events_str_ptr,
799 bool has_more_events) {
800 if (events_str_ptr->data().size())
801 OnTraceDataCollected(events_str_ptr);
803 if (has_more_events)
804 return;
806 // Simulate an DisableRecordingAcked for the local trace.
807 std::vector<std::string> category_groups;
808 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
809 OnDisableRecordingAcked(NULL, category_groups);
812 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
813 const scoped_refptr<base::RefCountedString>& events_str_ptr,
814 bool has_more_events) {
815 if (events_str_ptr->data().size())
816 OnMonitoringTraceDataCollected(events_str_ptr);
818 if (has_more_events)
819 return;
821 // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
822 OnCaptureMonitoringSnapshotAcked(NULL);
825 void TracingControllerImpl::OnTraceLogStatusReply(
826 TraceMessageFilter* trace_message_filter,
827 const base::trace_event::TraceLogStatus& status) {
828 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
829 BrowserThread::PostTask(
830 BrowserThread::UI, FROM_HERE,
831 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
832 base::Unretained(this),
833 make_scoped_refptr(trace_message_filter), status));
834 return;
837 if (pending_trace_log_status_ack_count_ == 0)
838 return;
840 if (trace_message_filter &&
841 !pending_trace_log_status_filters_.erase(trace_message_filter)) {
842 // The response from the specified message filter has already been received.
843 return;
846 float percent_full = static_cast<float>(
847 static_cast<double>(status.event_count) / status.event_capacity);
848 maximum_trace_buffer_usage_ =
849 std::max(maximum_trace_buffer_usage_, percent_full);
850 approximate_event_count_ += status.event_count;
852 if (--pending_trace_log_status_ack_count_ == 0) {
853 // Trigger callback if one is set.
854 pending_trace_buffer_usage_callback_.Run(maximum_trace_buffer_usage_,
855 approximate_event_count_);
856 pending_trace_buffer_usage_callback_.Reset();
860 void TracingControllerImpl::OnWatchEventMatched() {
861 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
862 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
863 base::Bind(&TracingControllerImpl::OnWatchEventMatched,
864 base::Unretained(this)));
865 return;
868 if (!watch_event_callback_.is_null())
869 watch_event_callback_.Run();
872 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) {
873 DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end());
874 tracing_uis_.insert(tracing_ui);
877 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) {
878 std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui);
879 DCHECK(it != tracing_uis_.end());
880 tracing_uis_.erase(it);
883 void TracingControllerImpl::RequestGlobalMemoryDump(
884 const base::trace_event::MemoryDumpRequestArgs& args,
885 const base::trace_event::MemoryDumpCallback& callback) {
886 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
887 BrowserThread::PostTask(
888 BrowserThread::UI, FROM_HERE,
889 base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump,
890 base::Unretained(this), args, callback));
891 return;
893 // TODO(primiano): send a local dump request to each of the child processes
894 // and do the bookkeeping to keep track of the outstanding requests.
895 // Also, at this point, this should check for collisions and bail out if a
896 // global dump is requested while another is already in progress.
897 NOTIMPLEMENTED();
900 void TracingControllerImpl::OnProcessMemoryDumpResponse(
901 TraceMessageFilter* trace_message_filter,
902 uint64 dump_guid,
903 bool success) {
904 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
905 BrowserThread::PostTask(
906 BrowserThread::UI, FROM_HERE,
907 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
908 base::Unretained(this),
909 make_scoped_refptr(trace_message_filter), dump_guid,
910 success));
911 return;
913 // TODO(primiano): update the bookkeeping structs and, if this was the
914 // response from the last pending child, fire the completion callback, which
915 // in turn will cause a GlobalMemoryDumpResponse message to be sent back to
916 // the child, if this global dump was NOT initiated by the browser.
917 NOTIMPLEMENTED();
920 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
921 if (is_monitoring_ == is_monitoring)
922 return;
924 is_monitoring_ = is_monitoring;
925 #if !defined(OS_ANDROID)
926 for (std::set<TracingUI*>::iterator it = tracing_uis_.begin();
927 it != tracing_uis_.end(); it++) {
928 (*it)->OnMonitoringStateChanged(is_monitoring);
930 #endif
933 } // namespace content