Home | History | Annotate | Download | only in tracing
      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 
     27 using base::debug::TraceLog;
     28 using base::debug::TraceOptions;
     29 using base::debug::CategoryFilter;
     30 
     31 namespace content {
     32 
     33 namespace {
     34 
     35 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
     36     LAZY_INSTANCE_INITIALIZER;
     37 
     38 class 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 
    122 class 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 
    161 TracingController* TracingController::GetInstance() {
    162   return TracingControllerImpl::GetInstance();
    163 }
    164 
    165 TracingControllerImpl::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 
    179 TracingControllerImpl::~TracingControllerImpl() {
    180   // This is a Leaky instance.
    181   NOTREACHED();
    182 }
    183 
    184 TracingControllerImpl* TracingControllerImpl::GetInstance() {
    185   return g_controller.Pointer();
    186 }
    187 
    188 bool 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 
    207 void 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 
    219 void TracingControllerImpl::SetDisabledOnFileThread(
    220     const base::Closure& callback) {
    221   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    222 
    223   TraceLog::GetInstance()->SetDisabled();
    224   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
    225 }
    226 
    227 bool TracingControllerImpl::EnableRecording(
    228     const 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 
    272 void 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 
    288 bool 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 
    308 void 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 
    361 bool 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 
    391 void 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 
    407 bool 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 
    425 scoped_refptr<TracingController::TraceDataSink>
    426 TracingController::CreateStringSink(
    427     const base::Callback<void(base::RefCountedString*)>& callback) {
    428   return new StringTraceDataSink(callback);
    429 }
    430 
    431 scoped_refptr<TracingController::TraceDataSink>
    432 TracingController::CreateFileSink(const base::FilePath& file_path,
    433                                   const base::Closure& callback) {
    434   return new FileTraceDataSink(file_path, callback);
    435 }
    436 
    437 void 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 
    452 void 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 
    461 bool 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 
    502 bool 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 
    534 bool 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 
    559 bool 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 
    574 void 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 
    601 void 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 
    650 void 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)
    703 void 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 
    724 void 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 
    762 void 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 
    777 void 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 
    790 void 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 
    805 void 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 
    818 void 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 
    850 void 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 
    862 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) {
    863   DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end());
    864   tracing_uis_.insert(tracing_ui);
    865 }
    866 
    867 void 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 
    873 void 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