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