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