Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / tracing / tracing_controller_impl.cc
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"
5
6 #include "base/bind.h"
7 #include "base/debug/trace_event.h"
8 #include "base/files/file_util.h"
9 #include "base/json/string_escape.h"
10 #include "base/macros.h"
11 #include "base/strings/string_number_conversions.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"
17
18 #if defined(OS_CHROMEOS)
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/debug_daemon_client.h"
21 #endif
22
23 #if defined(OS_WIN)
24 #include "content/browser/tracing/etw_system_event_consumer_win.h"
25 #endif
26
27 using base::debug::TraceLog;
28 using base::debug::TraceOptions;
29 using base::debug::CategoryFilter;
30
31 namespace content {
32
33 namespace {
34
35 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
36     LAZY_INSTANCE_INITIALIZER;
37
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) {}
45
46   virtual 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));
55   }
56   virtual void SetSystemTrace(const std::string& data) OVERRIDE {
57     system_trace_ = data;
58   }
59   virtual void Close() OVERRIDE {
60     BrowserThread::PostTask(
61         BrowserThread::FILE,
62         FROM_HERE,
63         base::Bind(&FileTraceDataSink::CloseOnFileThread, this));
64   }
65
66  private:
67   virtual ~FileTraceDataSink() { DCHECK(file_ == NULL); }
68
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_));
77   }
78
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;
86     }
87     const char preamble[] = "{\"traceEvents\": [";
88     ignore_result(fwrite(preamble, strlen(preamble), 1, file_));
89     return true;
90   }
91
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_));
101       }
102       fputc('}', file_);
103       base::CloseFile(file_);
104       file_ = NULL;
105     }
106     BrowserThread::PostTask(
107         BrowserThread::UI,
108         FROM_HERE,
109         base::Bind(&FileTraceDataSink::FinalizeOnUIThread, this));
110   }
111
112   void FinalizeOnUIThread() { completion_callback_.Run(); }
113
114   base::FilePath file_path_;
115   base::Closure completion_callback_;
116   FILE* file_;
117   std::string system_trace_;
118
119   DISALLOW_COPY_AND_ASSIGN(FileTraceDataSink);
120 };
121
122 class StringTraceDataSink : public TracingController::TraceDataSink {
123  public:
124   typedef base::Callback<void(base::RefCountedString*)> CompletionCallback;
125
126   explicit StringTraceDataSink(CompletionCallback callback)
127       : completion_callback_(callback) {}
128
129   // TracingController::TraceDataSink implementation
130   virtual void AddTraceChunk(const std::string& chunk) OVERRIDE {
131     if (!trace_.empty())
132       trace_ += ",";
133     trace_ += chunk;
134   }
135   virtual void SetSystemTrace(const std::string& data) OVERRIDE {
136     system_trace_ = data;
137   }
138   virtual void Close() OVERRIDE {
139     std::string result = "{\"traceEvents\":[" + trace_ + "]";
140     if (!system_trace_.empty())
141       result += ",\"systemTraceEvents\": " + system_trace_;
142     result += "}";
143
144     scoped_refptr<base::RefCountedString> str =
145         base::RefCountedString::TakeString(&result);
146     completion_callback_.Run(str.get());
147   }
148
149  private:
150   virtual ~StringTraceDataSink() {}
151
152   std::string trace_;
153   std::string system_trace_;
154   CompletionCallback completion_callback_;
155
156   DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink);
157 };
158
159 }  // namespace
160
161 TracingController* TracingController::GetInstance() {
162   return TracingControllerImpl::GetInstance();
163 }
164
165 TracingControllerImpl::TracingControllerImpl() :
166     pending_disable_recording_ack_count_(0),
167     pending_capture_monitoring_snapshot_ack_count_(0),
168     pending_trace_buffer_percent_full_ack_count_(0),
169     maximum_trace_buffer_percent_full_(0),
170     // Tracing may have been enabled by ContentMainRunner if kTraceStartup
171     // is specified in command line.
172 #if defined(OS_CHROMEOS) || defined(OS_WIN)
173     is_system_tracing_(false),
174 #endif
175     is_recording_(TraceLog::GetInstance()->IsEnabled()),
176     is_monitoring_(false) {
177 }
178
179 TracingControllerImpl::~TracingControllerImpl() {
180   // This is a Leaky instance.
181   NOTREACHED();
182 }
183
184 TracingControllerImpl* TracingControllerImpl::GetInstance() {
185   return g_controller.Pointer();
186 }
187
188 bool TracingControllerImpl::GetCategories(
189     const GetCategoriesDoneCallback& callback) {
190   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
191
192   // Known categories come back from child processes with the EndTracingAck
193   // message. So to get known categories, just begin and end tracing immediately
194   // afterwards. This will ping all the child processes for categories.
195   pending_get_categories_done_callback_ = callback;
196   if (!EnableRecording(
197           CategoryFilter("*"), TraceOptions(), EnableRecordingDoneCallback())) {
198     pending_get_categories_done_callback_.Reset();
199     return false;
200   }
201
202   bool ok = DisableRecording(NULL);
203   DCHECK(ok);
204   return true;
205 }
206
207 void TracingControllerImpl::SetEnabledOnFileThread(
208     const CategoryFilter& category_filter,
209     int mode,
210     const TraceOptions& trace_options,
211     const base::Closure& callback) {
212   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
213
214   TraceLog::GetInstance()->SetEnabled(
215       category_filter, static_cast<TraceLog::Mode>(mode), trace_options);
216   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
217 }
218
219 void TracingControllerImpl::SetDisabledOnFileThread(
220     const base::Closure& callback) {
221   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
222
223   TraceLog::GetInstance()->SetDisabled();
224   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
225 }
226
227 bool TracingControllerImpl::EnableRecording(
228     const CategoryFilter& category_filter,
229     const TraceOptions& trace_options,
230     const EnableRecordingDoneCallback& callback) {
231   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
232
233   if (!can_enable_recording())
234     return false;
235   is_recording_ = true;
236
237 #if defined(OS_ANDROID)
238   if (pending_get_categories_done_callback_.is_null())
239     TraceLog::GetInstance()->AddClockSyncMetadataEvent();
240 #endif
241
242   trace_options_ = trace_options;
243
244   if (trace_options.enable_systrace) {
245 #if defined(OS_CHROMEOS)
246     DCHECK(!is_system_tracing_);
247     chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
248       StartSystemTracing();
249     is_system_tracing_ = true;
250 #elif defined(OS_WIN)
251     DCHECK(!is_system_tracing_);
252     is_system_tracing_ =
253         EtwSystemEventConsumer::GetInstance()->StartSystemTracing();
254 #endif
255   }
256
257
258   base::Closure on_enable_recording_done_callback =
259       base::Bind(&TracingControllerImpl::OnEnableRecordingDone,
260                  base::Unretained(this),
261                  category_filter, trace_options, callback);
262   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
263       base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
264                  base::Unretained(this),
265                  category_filter,
266                  base::debug::TraceLog::RECORDING_MODE,
267                  trace_options,
268                  on_enable_recording_done_callback));
269   return true;
270 }
271
272 void TracingControllerImpl::OnEnableRecordingDone(
273     const CategoryFilter& category_filter,
274     const TraceOptions& trace_options,
275     const EnableRecordingDoneCallback& callback) {
276   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
277
278   // Notify all child processes.
279   for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
280       it != trace_message_filters_.end(); ++it) {
281     it->get()->SendBeginTracing(category_filter, trace_options);
282   }
283
284   if (!callback.is_null())
285     callback.Run();
286 }
287
288 bool TracingControllerImpl::DisableRecording(
289     const scoped_refptr<TraceDataSink>& trace_data_sink) {
290   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
291
292   if (!can_disable_recording())
293     return false;
294
295   trace_data_sink_ = trace_data_sink;
296   trace_options_ = TraceOptions();
297   // Disable local trace early to avoid traces during end-tracing process from
298   // interfering with the process.
299   base::Closure on_disable_recording_done_callback = base::Bind(
300       &TracingControllerImpl::OnDisableRecordingDone, base::Unretained(this));
301   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
302       base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
303                  base::Unretained(this),
304                  on_disable_recording_done_callback));
305   return true;
306 }
307
308 void TracingControllerImpl::OnDisableRecordingDone() {
309   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
310
311 #if defined(OS_ANDROID)
312   if (pending_get_categories_done_callback_.is_null())
313     TraceLog::GetInstance()->AddClockSyncMetadataEvent();
314 #endif
315
316   // Count myself (local trace) in pending_disable_recording_ack_count_,
317   // acked below.
318   pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
319   pending_disable_recording_filters_ = trace_message_filters_;
320
321 #if defined(OS_CHROMEOS) || defined(OS_WIN)
322   if (is_system_tracing_) {
323     // Disable system tracing.
324     is_system_tracing_ = false;
325     ++pending_disable_recording_ack_count_;
326
327 #if defined(OS_CHROMEOS)
328     scoped_refptr<base::TaskRunner> task_runner =
329         BrowserThread::GetBlockingPool();
330     chromeos::DBusThreadManager::Get()
331         ->GetDebugDaemonClient()
332         ->RequestStopSystemTracing(
333             task_runner,
334             base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
335                        base::Unretained(this)));
336 #elif defined(OS_WIN)
337     EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
338         base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
339                    base::Unretained(this)));
340 #endif
341   }
342 #endif  // defined(OS_CHROMEOS) || defined(OS_WIN)
343
344   // Handle special case of zero child processes by immediately flushing the
345   // trace log. Once the flush has completed the caller will be notified that
346   // tracing has ended.
347   if (pending_disable_recording_ack_count_ == 1) {
348     // Flush asynchronously now, because we don't have any children to wait for.
349     TraceLog::GetInstance()->Flush(
350         base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
351                    base::Unretained(this)));
352   }
353
354   // Notify all child processes.
355   for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
356       it != trace_message_filters_.end(); ++it) {
357     it->get()->SendEndTracing();
358   }
359 }
360
361 bool TracingControllerImpl::EnableMonitoring(
362     const CategoryFilter& category_filter,
363     const TraceOptions& trace_options,
364     const EnableMonitoringDoneCallback& callback) {
365   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
366
367   if (!can_enable_monitoring())
368     return false;
369   OnMonitoringStateChanged(true);
370
371 #if defined(OS_ANDROID)
372   TraceLog::GetInstance()->AddClockSyncMetadataEvent();
373 #endif
374
375   trace_options_ = trace_options;
376
377   base::Closure on_enable_monitoring_done_callback =
378       base::Bind(&TracingControllerImpl::OnEnableMonitoringDone,
379                  base::Unretained(this),
380                  category_filter, trace_options, callback);
381   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
382       base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
383                  base::Unretained(this),
384                  category_filter,
385                  base::debug::TraceLog::MONITORING_MODE,
386                  trace_options,
387                  on_enable_monitoring_done_callback));
388   return true;
389 }
390
391 void TracingControllerImpl::OnEnableMonitoringDone(
392     const CategoryFilter& category_filter,
393     const TraceOptions& trace_options,
394     const EnableMonitoringDoneCallback& callback) {
395   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
396
397   // Notify all child processes.
398   for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
399       it != trace_message_filters_.end(); ++it) {
400     it->get()->SendEnableMonitoring(category_filter, trace_options);
401   }
402
403   if (!callback.is_null())
404     callback.Run();
405 }
406
407 bool TracingControllerImpl::DisableMonitoring(
408     const DisableMonitoringDoneCallback& callback) {
409   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
410
411   if (!can_disable_monitoring())
412     return false;
413
414   trace_options_ = TraceOptions();
415   base::Closure on_disable_monitoring_done_callback =
416       base::Bind(&TracingControllerImpl::OnDisableMonitoringDone,
417                  base::Unretained(this), callback);
418   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
419       base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
420                  base::Unretained(this),
421                  on_disable_monitoring_done_callback));
422   return true;
423 }
424
425 scoped_refptr<TracingController::TraceDataSink>
426 TracingController::CreateStringSink(
427     const base::Callback<void(base::RefCountedString*)>& callback) {
428   return new StringTraceDataSink(callback);
429 }
430
431 scoped_refptr<TracingController::TraceDataSink>
432 TracingController::CreateFileSink(const base::FilePath& file_path,
433                                   const base::Closure& callback) {
434   return new FileTraceDataSink(file_path, callback);
435 }
436
437 void TracingControllerImpl::OnDisableMonitoringDone(
438     const DisableMonitoringDoneCallback& callback) {
439   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
440
441   OnMonitoringStateChanged(false);
442
443   // Notify all child processes.
444   for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
445       it != trace_message_filters_.end(); ++it) {
446     it->get()->SendDisableMonitoring();
447   }
448   if (!callback.is_null())
449     callback.Run();
450 }
451
452 void TracingControllerImpl::GetMonitoringStatus(
453     bool* out_enabled,
454     CategoryFilter* out_category_filter,
455     TraceOptions* out_trace_options) {
456   *out_enabled = is_monitoring_;
457   *out_category_filter = TraceLog::GetInstance()->GetCurrentCategoryFilter();
458   *out_trace_options = trace_options_;
459 }
460
461 bool TracingControllerImpl::CaptureMonitoringSnapshot(
462     const scoped_refptr<TraceDataSink>& monitoring_data_sink) {
463   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
464
465   if (!can_disable_monitoring())
466     return false;
467
468   if (!monitoring_data_sink.get())
469     return false;
470
471   monitoring_data_sink_ = monitoring_data_sink;
472
473   // Count myself in pending_capture_monitoring_snapshot_ack_count_,
474   // acked below.
475   pending_capture_monitoring_snapshot_ack_count_ =
476       trace_message_filters_.size() + 1;
477   pending_capture_monitoring_filters_ = trace_message_filters_;
478
479   // Handle special case of zero child processes by immediately flushing the
480   // trace log. Once the flush has completed the caller will be notified that
481   // the capture snapshot has ended.
482   if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
483     // Flush asynchronously now, because we don't have any children to wait for.
484     TraceLog::GetInstance()->FlushButLeaveBufferIntact(
485         base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
486                    base::Unretained(this)));
487   }
488
489   // Notify all child processes.
490   for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
491       it != trace_message_filters_.end(); ++it) {
492     it->get()->SendCaptureMonitoringSnapshot();
493   }
494
495 #if defined(OS_ANDROID)
496   TraceLog::GetInstance()->AddClockSyncMetadataEvent();
497 #endif
498
499   return true;
500 }
501
502 bool TracingControllerImpl::GetTraceBufferPercentFull(
503     const GetTraceBufferPercentFullCallback& callback) {
504   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
505
506   if (!can_get_trace_buffer_percent_full() || callback.is_null())
507     return false;
508
509   pending_trace_buffer_percent_full_callback_ = callback;
510
511   // Count myself in pending_trace_buffer_percent_full_ack_count_, acked below.
512   pending_trace_buffer_percent_full_ack_count_ =
513       trace_message_filters_.size() + 1;
514   pending_trace_buffer_percent_full_filters_ = trace_message_filters_;
515   maximum_trace_buffer_percent_full_ = 0;
516
517   // Call OnTraceBufferPercentFullReply unconditionally for the browser process.
518   // This will result in immediate execution of the callback if there are no
519   // child processes.
520   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
521       base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
522                   base::Unretained(this),
523                   scoped_refptr<TraceMessageFilter>(),
524                   TraceLog::GetInstance()->GetBufferPercentFull()));
525
526   // Notify all child processes.
527   for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
528       it != trace_message_filters_.end(); ++it) {
529     it->get()->SendGetTraceBufferPercentFull();
530   }
531   return true;
532 }
533
534 bool TracingControllerImpl::SetWatchEvent(
535     const std::string& category_name,
536     const std::string& event_name,
537     const WatchEventCallback& callback) {
538   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
539
540   if (callback.is_null())
541     return false;
542
543   watch_category_name_ = category_name;
544   watch_event_name_ = event_name;
545   watch_event_callback_ = callback;
546
547   TraceLog::GetInstance()->SetWatchEvent(
548       category_name, event_name,
549       base::Bind(&TracingControllerImpl::OnWatchEventMatched,
550                  base::Unretained(this)));
551
552   for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
553       it != trace_message_filters_.end(); ++it) {
554     it->get()->SendSetWatchEvent(category_name, event_name);
555   }
556   return true;
557 }
558
559 bool TracingControllerImpl::CancelWatchEvent() {
560   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
561
562   if (!can_cancel_watch_event())
563     return false;
564
565   for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
566       it != trace_message_filters_.end(); ++it) {
567     it->get()->SendCancelWatchEvent();
568   }
569
570   watch_event_callback_.Reset();
571   return true;
572 }
573
574 void TracingControllerImpl::AddTraceMessageFilter(
575     TraceMessageFilter* trace_message_filter) {
576   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
577     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
578         base::Bind(&TracingControllerImpl::AddTraceMessageFilter,
579                    base::Unretained(this),
580                    make_scoped_refptr(trace_message_filter)));
581     return;
582   }
583
584   trace_message_filters_.insert(trace_message_filter);
585   if (can_cancel_watch_event()) {
586     trace_message_filter->SendSetWatchEvent(watch_category_name_,
587                                             watch_event_name_);
588   }
589   if (can_disable_recording()) {
590     trace_message_filter->SendBeginTracing(
591         TraceLog::GetInstance()->GetCurrentCategoryFilter(),
592         TraceLog::GetInstance()->GetCurrentTraceOptions());
593   }
594   if (can_disable_monitoring()) {
595     trace_message_filter->SendEnableMonitoring(
596         TraceLog::GetInstance()->GetCurrentCategoryFilter(),
597         TraceLog::GetInstance()->GetCurrentTraceOptions());
598   }
599 }
600
601 void TracingControllerImpl::RemoveTraceMessageFilter(
602     TraceMessageFilter* trace_message_filter) {
603   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
604     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
605         base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter,
606                    base::Unretained(this),
607                    make_scoped_refptr(trace_message_filter)));
608     return;
609   }
610
611   // If a filter is removed while a response from that filter is pending then
612   // simulate the response. Otherwise the response count will be wrong and the
613   // completion callback will never be executed.
614   if (pending_disable_recording_ack_count_ > 0) {
615     TraceMessageFilterSet::const_iterator it =
616         pending_disable_recording_filters_.find(trace_message_filter);
617     if (it != pending_disable_recording_filters_.end()) {
618       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
619           base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
620                      base::Unretained(this),
621                      make_scoped_refptr(trace_message_filter),
622                      std::vector<std::string>()));
623     }
624   }
625   if (pending_capture_monitoring_snapshot_ack_count_ > 0) {
626     TraceMessageFilterSet::const_iterator it =
627         pending_capture_monitoring_filters_.find(trace_message_filter);
628     if (it != pending_capture_monitoring_filters_.end()) {
629       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
630           base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
631                      base::Unretained(this),
632                      make_scoped_refptr(trace_message_filter)));
633     }
634   }
635   if (pending_trace_buffer_percent_full_ack_count_ > 0) {
636     TraceMessageFilterSet::const_iterator it =
637         pending_trace_buffer_percent_full_filters_.find(trace_message_filter);
638     if (it != pending_trace_buffer_percent_full_filters_.end()) {
639       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
640           base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
641                      base::Unretained(this),
642                      make_scoped_refptr(trace_message_filter),
643                      0));
644     }
645   }
646
647   trace_message_filters_.erase(trace_message_filter);
648 }
649
650 void TracingControllerImpl::OnDisableRecordingAcked(
651     TraceMessageFilter* trace_message_filter,
652     const std::vector<std::string>& known_category_groups) {
653   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
654     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
655         base::Bind(&TracingControllerImpl::OnDisableRecordingAcked,
656                    base::Unretained(this),
657                    make_scoped_refptr(trace_message_filter),
658                    known_category_groups));
659     return;
660   }
661
662   // Merge known_category_groups with known_category_groups_
663   known_category_groups_.insert(known_category_groups.begin(),
664                                 known_category_groups.end());
665
666   if (pending_disable_recording_ack_count_ == 0)
667     return;
668
669   if (trace_message_filter &&
670       !pending_disable_recording_filters_.erase(trace_message_filter)) {
671     // The response from the specified message filter has already been received.
672     return;
673   }
674
675   if (--pending_disable_recording_ack_count_ == 1) {
676     // All acks from subprocesses have been received. Now flush the local trace.
677     // During or after this call, our OnLocalTraceDataCollected will be
678     // called with the last of the local trace data.
679     TraceLog::GetInstance()->Flush(
680         base::Bind(&TracingControllerImpl::OnLocalTraceDataCollected,
681                    base::Unretained(this)));
682     return;
683   }
684
685   if (pending_disable_recording_ack_count_ != 0)
686     return;
687
688   // All acks (including from the subprocesses and the local trace) have been
689   // received.
690   is_recording_ = false;
691
692   // Trigger callback if one is set.
693   if (!pending_get_categories_done_callback_.is_null()) {
694     pending_get_categories_done_callback_.Run(known_category_groups_);
695     pending_get_categories_done_callback_.Reset();
696   } else if (trace_data_sink_.get()) {
697     trace_data_sink_->Close();
698     trace_data_sink_ = NULL;
699   }
700 }
701
702 #if defined(OS_CHROMEOS) || defined(OS_WIN)
703 void TracingControllerImpl::OnEndSystemTracingAcked(
704     const scoped_refptr<base::RefCountedString>& events_str_ptr) {
705   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
706
707   if (trace_data_sink_.get()) {
708 #if defined(OS_WIN)
709     // The Windows kernel events are kept into a JSon format stored as string
710     // and must not be escaped.
711     std::string json_string = events_str_ptr->data();
712 #else
713     std::string json_string =
714         base::GetQuotedJSONString(events_str_ptr->data());
715 #endif
716     trace_data_sink_->SetSystemTrace(json_string);
717   }
718   DCHECK(!is_system_tracing_);
719   std::vector<std::string> category_groups;
720   OnDisableRecordingAcked(NULL, category_groups);
721 }
722 #endif
723
724 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
725     TraceMessageFilter* trace_message_filter) {
726   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
727     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
728         base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
729                    base::Unretained(this),
730                    make_scoped_refptr(trace_message_filter)));
731     return;
732   }
733
734   if (pending_capture_monitoring_snapshot_ack_count_ == 0)
735     return;
736
737   if (trace_message_filter &&
738       !pending_capture_monitoring_filters_.erase(trace_message_filter)) {
739     // The response from the specified message filter has already been received.
740     return;
741   }
742
743   if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
744     // All acks from subprocesses have been received. Now flush the local trace.
745     // During or after this call, our OnLocalMonitoringTraceDataCollected
746     // will be called with the last of the local trace data.
747     TraceLog::GetInstance()->FlushButLeaveBufferIntact(
748         base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
749                    base::Unretained(this)));
750     return;
751   }
752
753   if (pending_capture_monitoring_snapshot_ack_count_ != 0)
754     return;
755
756   if (monitoring_data_sink_.get()) {
757     monitoring_data_sink_->Close();
758     monitoring_data_sink_ = NULL;
759   }
760 }
761
762 void TracingControllerImpl::OnTraceDataCollected(
763     const scoped_refptr<base::RefCountedString>& events_str_ptr) {
764   // OnTraceDataCollected may be called from any browser thread, either by the
765   // local event trace system or from child processes via TraceMessageFilter.
766   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
767     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
768         base::Bind(&TracingControllerImpl::OnTraceDataCollected,
769                    base::Unretained(this), events_str_ptr));
770     return;
771   }
772
773   if (trace_data_sink_.get())
774     trace_data_sink_->AddTraceChunk(events_str_ptr->data());
775 }
776
777 void TracingControllerImpl::OnMonitoringTraceDataCollected(
778     const scoped_refptr<base::RefCountedString>& events_str_ptr) {
779   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
780     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
781         base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
782                    base::Unretained(this), events_str_ptr));
783     return;
784   }
785
786   if (monitoring_data_sink_.get())
787     monitoring_data_sink_->AddTraceChunk(events_str_ptr->data());
788 }
789
790 void TracingControllerImpl::OnLocalTraceDataCollected(
791     const scoped_refptr<base::RefCountedString>& events_str_ptr,
792     bool has_more_events) {
793   if (events_str_ptr->data().size())
794     OnTraceDataCollected(events_str_ptr);
795
796   if (has_more_events)
797     return;
798
799   // Simulate an DisableRecordingAcked for the local trace.
800   std::vector<std::string> category_groups;
801   TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
802   OnDisableRecordingAcked(NULL, category_groups);
803 }
804
805 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
806     const scoped_refptr<base::RefCountedString>& events_str_ptr,
807     bool has_more_events) {
808   if (events_str_ptr->data().size())
809     OnMonitoringTraceDataCollected(events_str_ptr);
810
811   if (has_more_events)
812     return;
813
814   // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
815   OnCaptureMonitoringSnapshotAcked(NULL);
816 }
817
818 void TracingControllerImpl::OnTraceBufferPercentFullReply(
819     TraceMessageFilter* trace_message_filter,
820     float percent_full) {
821   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
822     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
823         base::Bind(&TracingControllerImpl::OnTraceBufferPercentFullReply,
824                    base::Unretained(this),
825                    make_scoped_refptr(trace_message_filter),
826                    percent_full));
827     return;
828   }
829
830   if (pending_trace_buffer_percent_full_ack_count_ == 0)
831     return;
832
833   if (trace_message_filter &&
834       !pending_trace_buffer_percent_full_filters_.erase(trace_message_filter)) {
835     // The response from the specified message filter has already been received.
836     return;
837   }
838
839   maximum_trace_buffer_percent_full_ =
840       std::max(maximum_trace_buffer_percent_full_, percent_full);
841
842   if (--pending_trace_buffer_percent_full_ack_count_ == 0) {
843     // Trigger callback if one is set.
844     pending_trace_buffer_percent_full_callback_.Run(
845         maximum_trace_buffer_percent_full_);
846     pending_trace_buffer_percent_full_callback_.Reset();
847   }
848 }
849
850 void TracingControllerImpl::OnWatchEventMatched() {
851   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
852     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
853         base::Bind(&TracingControllerImpl::OnWatchEventMatched,
854                    base::Unretained(this)));
855     return;
856   }
857
858   if (!watch_event_callback_.is_null())
859     watch_event_callback_.Run();
860 }
861
862 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) {
863   DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end());
864   tracing_uis_.insert(tracing_ui);
865 }
866
867 void TracingControllerImpl::UnregisterTracingUI(TracingUI* tracing_ui) {
868   std::set<TracingUI*>::iterator it = tracing_uis_.find(tracing_ui);
869   DCHECK(it != tracing_uis_.end());
870   tracing_uis_.erase(it);
871 }
872
873 void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
874   if (is_monitoring_ == is_monitoring)
875     return;
876
877   is_monitoring_ = is_monitoring;
878 #if !defined(OS_ANDROID)
879   for (std::set<TracingUI*>::iterator it = tracing_uis_.begin();
880        it != tracing_uis_.end(); it++) {
881     (*it)->OnMonitoringStateChanged(is_monitoring);
882   }
883 #endif
884 }
885
886 }  // namespace content