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