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/file_util.h"
      8 #include "base/files/file_path.h"
      9 #include "base/memory/singleton.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/timer/timer.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "content/public/browser/tracing_controller.h"
     15 #include "content/public/test/test_utils.h"
     16 
     17 namespace {
     18 
     19 using content::BrowserThread;
     20 
     21 class InProcessTraceController {
     22  public:
     23   static InProcessTraceController* GetInstance() {
     24     return Singleton<InProcessTraceController>::get();
     25   }
     26 
     27   InProcessTraceController()
     28       : is_waiting_on_watch_(false),
     29         watch_notification_count_(0) {}
     30   virtual ~InProcessTraceController() {}
     31 
     32   bool BeginTracing(const std::string& category_patterns) {
     33     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     34     return content::TracingController::GetInstance()->EnableRecording(
     35         category_patterns, content::TracingController::DEFAULT_OPTIONS,
     36         content::TracingController::EnableRecordingDoneCallback());
     37     return true;
     38   }
     39 
     40   bool BeginTracingWithWatch(const std::string& category_patterns,
     41                              const std::string& category_name,
     42                              const std::string& event_name,
     43                              int num_occurrences) {
     44     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     45     DCHECK(num_occurrences > 0);
     46     watch_notification_count_ = num_occurrences;
     47     return content::TracingController::GetInstance()->SetWatchEvent(
     48         category_name, event_name,
     49         base::Bind(&InProcessTraceController::OnWatchEventMatched,
     50                    base::Unretained(this))) &&
     51         BeginTracing(category_patterns);
     52   }
     53 
     54   bool WaitForWatchEvent(base::TimeDelta timeout) {
     55     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     56     if (watch_notification_count_ == 0)
     57       return true;
     58 
     59     if (timeout != base::TimeDelta()) {
     60       timer_.Start(FROM_HERE, timeout, this,
     61                    &InProcessTraceController::Timeout);
     62     }
     63 
     64     is_waiting_on_watch_ = true;
     65     message_loop_runner_ = new content::MessageLoopRunner;
     66     message_loop_runner_->Run();
     67     is_waiting_on_watch_ = false;
     68 
     69     return watch_notification_count_ == 0;
     70   }
     71 
     72   bool EndTracing(std::string* json_trace_output) {
     73     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     74     using namespace base::debug;
     75 
     76     if (!content::TracingController::GetInstance()->DisableRecording(
     77         base::FilePath(),
     78         base::Bind(&InProcessTraceController::OnTraceDataCollected,
     79                    base::Unretained(this),
     80                    base::Unretained(json_trace_output))))
     81       return false;
     82 
     83     // Wait for OnEndTracingComplete() to quit the message loop.
     84     message_loop_runner_ = new content::MessageLoopRunner;
     85     message_loop_runner_->Run();
     86 
     87     // Watch notifications can occur during this method's message loop run, but
     88     // not after, so clear them here.
     89     watch_notification_count_ = 0;
     90     return true;
     91   }
     92 
     93  private:
     94   friend struct DefaultSingletonTraits<InProcessTraceController>;
     95 
     96   void OnEndTracingComplete() {
     97     message_loop_runner_->Quit();
     98   }
     99 
    100   void OnTraceDataCollected(std::string* json_trace_output,
    101                             const base::FilePath& path) {
    102     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    103         base::Bind(&InProcessTraceController::ReadTraceData,
    104                    base::Unretained(this),
    105                    base::Unretained(json_trace_output),
    106                    path));
    107   }
    108 
    109   void ReadTraceData(std::string* json_trace_output,
    110                      const base::FilePath& path) {
    111     json_trace_output->clear();
    112     bool ok = base::ReadFileToString(path, json_trace_output);
    113     DCHECK(ok);
    114     base::DeleteFile(path, false);
    115 
    116     // The callers expect an array of trace events.
    117     const char* preamble = "{\"traceEvents\": ";
    118     const char* trailout = "}";
    119     DCHECK(StartsWithASCII(*json_trace_output, preamble, true));
    120     DCHECK(EndsWith(*json_trace_output, trailout, true));
    121     json_trace_output->erase(0, strlen(preamble));
    122     json_trace_output->erase(json_trace_output->end() - 1);
    123 
    124     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    125         base::Bind(&InProcessTraceController::OnEndTracingComplete,
    126                    base::Unretained(this)));
    127   }
    128 
    129   void OnWatchEventMatched() {
    130     if (watch_notification_count_ == 0)
    131       return;
    132     if (--watch_notification_count_ == 0) {
    133       timer_.Stop();
    134       if (is_waiting_on_watch_)
    135         message_loop_runner_->Quit();
    136     }
    137   }
    138 
    139   void Timeout() {
    140     DCHECK(is_waiting_on_watch_);
    141     message_loop_runner_->Quit();
    142   }
    143 
    144   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
    145 
    146   base::OneShotTimer<InProcessTraceController> timer_;
    147 
    148   bool is_waiting_on_watch_;
    149   int watch_notification_count_;
    150 
    151   DISALLOW_COPY_AND_ASSIGN(InProcessTraceController);
    152 };
    153 
    154 }  // namespace
    155 
    156 namespace tracing {
    157 
    158 bool BeginTracing(const std::string& category_patterns) {
    159   return InProcessTraceController::GetInstance()->BeginTracing(
    160       category_patterns);
    161 }
    162 
    163 bool BeginTracingWithWatch(const std::string& category_patterns,
    164                            const std::string& category_name,
    165                            const std::string& event_name,
    166                            int num_occurrences) {
    167   return InProcessTraceController::GetInstance()->BeginTracingWithWatch(
    168       category_patterns, category_name, event_name, num_occurrences);
    169 }
    170 
    171 bool WaitForWatchEvent(base::TimeDelta timeout) {
    172   return InProcessTraceController::GetInstance()->WaitForWatchEvent(timeout);
    173 }
    174 
    175 bool EndTracing(std::string* json_trace_output) {
    176   return InProcessTraceController::GetInstance()->EndTracing(json_trace_output);
    177 }
    178 
    179 }  // namespace tracing
    180 
    181