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