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/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 
     26 using base::debug::TraceLog;
     27 
     28 namespace content {
     29 
     30 namespace {
     31 
     32 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
     33     LAZY_INSTANCE_INITIALIZER;
     34 
     35 }  // namespace
     36 
     37 TracingController* TracingController::GetInstance() {
     38   return TracingControllerImpl::GetInstance();
     39 }
     40 
     41 class 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 
     80 TracingControllerImpl::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 
     89 void 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 
    102 void 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 
    120 void TracingControllerImpl::ResultFile::WriteSystemTraceTask(
    121     const scoped_refptr<base::RefCountedString>& events_str_ptr) {
    122   system_trace_ = events_str_ptr;
    123 }
    124 
    125 void 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 
    163 TracingControllerImpl::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 
    177 TracingControllerImpl::~TracingControllerImpl() {
    178   // This is a Leaky instance.
    179   NOTREACHED();
    180 }
    181 
    182 TracingControllerImpl* TracingControllerImpl::GetInstance() {
    183   return g_controller.Pointer();
    184 }
    185 
    186 bool 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 
    205 void 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 
    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 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 
    277 void 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 
    294 bool 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 
    316 void 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 
    372 bool 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 
    405 void 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 
    422 bool 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 
    440 void 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 
    456 void 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 
    466 bool 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 
    509 bool 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 
    541 bool 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 
    566 bool 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 
    581 void 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 
    608 void 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 
    657 void 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 
    698 void 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 
    714 void 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)
    728 void 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 
    741 void 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 
    780 void 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 
    794 void 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 
    809 void 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 
    822 void 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 
    837 void 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 
    850 void 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 
    882 void 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 
    894 void TracingControllerImpl::RegisterTracingUI(TracingUI* tracing_ui) {
    895   DCHECK(tracing_uis_.find(tracing_ui) == tracing_uis_.end());
    896   tracing_uis_.insert(tracing_ui);
    897 }
    898 
    899 void 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 
    905 void 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