• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
StringTraceSink(std::string * result,const base::Closure & callback)24   StringTraceSink(std::string* result, const base::Closure& callback)
25       : result_(result), completion_callback_(callback) {}
26 
AddTraceChunk(const std::string & chunk)27   virtual void AddTraceChunk(const std::string& chunk) OVERRIDE {
28     *result_ += result_->empty() ? "[" : ",";
29     *result_ += chunk;
30   }
Close()31   virtual void Close() OVERRIDE {
32     if (!result_->empty())
33       *result_ += "]";
34     completion_callback_.Run();
35   }
36 
37  private:
~StringTraceSink()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:
GetInstance()48   static InProcessTraceController* GetInstance() {
49     return Singleton<InProcessTraceController>::get();
50   }
51 
InProcessTraceController()52   InProcessTraceController()
53       : is_waiting_on_watch_(false),
54         watch_notification_count_(0) {}
~InProcessTraceController()55   virtual ~InProcessTraceController() {}
56 
BeginTracing(const std::string & category_patterns)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 
BeginTracingWithWatch(const std::string & category_patterns,const std::string & category_name,const std::string & event_name,int num_occurrences)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 
WaitForWatchEvent(base::TimeDelta timeout)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 
EndTracing(std::string * json_trace_output)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 
OnEnableTracingComplete()133   void OnEnableTracingComplete() {
134     message_loop_runner_->Quit();
135   }
136 
OnTracingComplete()137   void OnTracingComplete() { message_loop_runner_->Quit(); }
138 
OnWatchEventMatched()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 
Timeout()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 
BeginTracing(const std::string & category_patterns)168 bool BeginTracing(const std::string& category_patterns) {
169   return InProcessTraceController::GetInstance()->BeginTracing(
170       category_patterns);
171 }
172 
BeginTracingWithWatch(const std::string & category_patterns,const std::string & category_name,const std::string & event_name,int num_occurrences)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 
WaitForWatchEvent(base::TimeDelta timeout)181 bool WaitForWatchEvent(base::TimeDelta timeout) {
182   return InProcessTraceController::GetInstance()->WaitForWatchEvent(timeout);
183 }
184 
EndTracing(std::string * json_trace_output)185 bool EndTracing(std::string* json_trace_output) {
186   return InProcessTraceController::GetInstance()->EndTracing(json_trace_output);
187 }
188 
189 }  // namespace tracing
190 
191