Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/test/base/tracing.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "base/files/file_path.h"
      9 #include "base/files/file_util.h"
     10 #include "base/memory/singleton.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/timer/timer.h"
     14 #include "content/public/browser/browser_thread.h"
     15 #include "content/public/browser/tracing_controller.h"
     16 #include "content/public/test/test_utils.h"
     17 
     18 namespace {
     19 
     20 using content::BrowserThread;
     21 
     22 class StringTraceSink : public content::TracingController::TraceDataSink {
     23  public:
     24   StringTraceSink(std::string* result, const base::Closure& callback)
     25       : result_(result), completion_callback_(callback) {}
     26 
     27   virtual void AddTraceChunk(const std::string& chunk) OVERRIDE {
     28     *result_ += result_->empty() ? "[" : ",";
     29     *result_ += chunk;
     30   }
     31   virtual void Close() OVERRIDE {
     32     if (!result_->empty())
     33       *result_ += "]";
     34     completion_callback_.Run();
     35   }
     36 
     37  private:
     38   virtual ~StringTraceSink() {}
     39 
     40   std::string* result_;
     41   base::Closure completion_callback_;
     42 
     43   DISALLOW_COPY_AND_ASSIGN(StringTraceSink);
     44 };
     45 
     46 class InProcessTraceController {
     47  public:
     48   static InProcessTraceController* GetInstance() {
     49     return Singleton<InProcessTraceController>::get();
     50   }
     51 
     52   InProcessTraceController()
     53       : is_waiting_on_watch_(false),
     54         watch_notification_count_(0) {}
     55   virtual ~InProcessTraceController() {}
     56 
     57   bool BeginTracing(const std::string& category_patterns) {
     58     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     59     return content::TracingController::GetInstance()->EnableRecording(
     60         base::debug::CategoryFilter(category_patterns),
     61         base::debug::TraceOptions(),
     62         content::TracingController::EnableRecordingDoneCallback());
     63   }
     64 
     65   bool BeginTracingWithWatch(const std::string& category_patterns,
     66                              const std::string& category_name,
     67                              const std::string& event_name,
     68                              int num_occurrences) {
     69     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     70     DCHECK(num_occurrences > 0);
     71     watch_notification_count_ = num_occurrences;
     72     if (!content::TracingController::GetInstance()->SetWatchEvent(
     73             category_name, event_name,
     74             base::Bind(&InProcessTraceController::OnWatchEventMatched,
     75                        base::Unretained(this)))) {
     76       return false;
     77     }
     78     if (!content::TracingController::GetInstance()->EnableRecording(
     79             base::debug::CategoryFilter(category_patterns),
     80             base::debug::TraceOptions(),
     81             base::Bind(&InProcessTraceController::OnEnableTracingComplete,
     82                        base::Unretained(this)))) {
     83       return false;
     84     }
     85 
     86     message_loop_runner_ = new content::MessageLoopRunner;
     87     message_loop_runner_->Run();
     88     return true;
     89   }
     90 
     91   bool WaitForWatchEvent(base::TimeDelta timeout) {
     92     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     93     if (watch_notification_count_ == 0)
     94       return true;
     95 
     96     if (timeout != base::TimeDelta()) {
     97       timer_.Start(FROM_HERE, timeout, this,
     98                    &InProcessTraceController::Timeout);
     99     }
    100 
    101     is_waiting_on_watch_ = true;
    102     message_loop_runner_ = new content::MessageLoopRunner;
    103     message_loop_runner_->Run();
    104     is_waiting_on_watch_ = false;
    105 
    106     return watch_notification_count_ == 0;
    107   }
    108 
    109   bool EndTracing(std::string* json_trace_output) {
    110     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    111     using namespace base::debug;
    112 
    113     if (!content::TracingController::GetInstance()->DisableRecording(
    114             new StringTraceSink(
    115                 json_trace_output,
    116                 base::Bind(&InProcessTraceController::OnTracingComplete,
    117                            base::Unretained(this))))) {
    118       return false;
    119     }
    120     // Wait for OnEndTracingComplete() to quit the message loop.
    121     message_loop_runner_ = new content::MessageLoopRunner;
    122     message_loop_runner_->Run();
    123 
    124     // Watch notifications can occur during this method's message loop run, but
    125     // not after, so clear them here.
    126     watch_notification_count_ = 0;
    127     return true;
    128   }
    129 
    130  private:
    131   friend struct DefaultSingletonTraits<InProcessTraceController>;
    132 
    133   void OnEnableTracingComplete() {
    134     message_loop_runner_->Quit();
    135   }
    136 
    137   void OnTracingComplete() { message_loop_runner_->Quit(); }
    138 
    139   void OnWatchEventMatched() {
    140     if (watch_notification_count_ == 0)
    141       return;
    142     if (--watch_notification_count_ == 0) {
    143       timer_.Stop();
    144       if (is_waiting_on_watch_)
    145         message_loop_runner_->Quit();
    146     }
    147   }
    148 
    149   void Timeout() {
    150     DCHECK(is_waiting_on_watch_);
    151     message_loop_runner_->Quit();
    152   }
    153 
    154   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
    155 
    156   base::OneShotTimer<InProcessTraceController> timer_;
    157 
    158   bool is_waiting_on_watch_;
    159   int watch_notification_count_;
    160 
    161   DISALLOW_COPY_AND_ASSIGN(InProcessTraceController);
    162 };
    163 
    164 }  // namespace
    165 
    166 namespace tracing {
    167 
    168 bool BeginTracing(const std::string& category_patterns) {
    169   return InProcessTraceController::GetInstance()->BeginTracing(
    170       category_patterns);
    171 }
    172 
    173 bool BeginTracingWithWatch(const std::string& category_patterns,
    174                            const std::string& category_name,
    175                            const std::string& event_name,
    176                            int num_occurrences) {
    177   return InProcessTraceController::GetInstance()->BeginTracingWithWatch(
    178       category_patterns, category_name, event_name, num_occurrences);
    179 }
    180 
    181 bool WaitForWatchEvent(base::TimeDelta timeout) {
    182   return InProcessTraceController::GetInstance()->WaitForWatchEvent(timeout);
    183 }
    184 
    185 bool EndTracing(std::string* json_trace_output) {
    186   return InProcessTraceController::GetInstance()->EndTracing(json_trace_output);
    187 }
    188 
    189 }  // namespace tracing
    190 
    191