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