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.
5 #include "chrome/test/base/tracing.h"
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"
19 using content::BrowserThread
;
21 class InProcessTraceController
{
23 static InProcessTraceController
* GetInstance() {
24 return Singleton
<InProcessTraceController
>::get();
27 InProcessTraceController()
28 : is_waiting_on_watch_(false),
29 watch_notification_count_(0) {}
30 virtual ~InProcessTraceController() {}
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());
39 bool BeginTracingWithWatch(const std::string
& category_patterns
,
40 const std::string
& category_name
,
41 const std::string
& event_name
,
42 int num_occurrences
) {
43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
44 DCHECK(num_occurrences
> 0);
45 watch_notification_count_
= num_occurrences
;
46 if (!content::TracingController::GetInstance()->SetWatchEvent(
47 category_name
, event_name
,
48 base::Bind(&InProcessTraceController::OnWatchEventMatched
,
49 base::Unretained(this)))) {
52 if (!content::TracingController::GetInstance()->EnableRecording(
53 category_patterns
, content::TracingController::DEFAULT_OPTIONS
,
54 base::Bind(&InProcessTraceController::OnEnableTracingComplete
,
55 base::Unretained(this)))) {
59 message_loop_runner_
= new content::MessageLoopRunner
;
60 message_loop_runner_
->Run();
64 bool WaitForWatchEvent(base::TimeDelta timeout
) {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
66 if (watch_notification_count_
== 0)
69 if (timeout
!= base::TimeDelta()) {
70 timer_
.Start(FROM_HERE
, timeout
, this,
71 &InProcessTraceController::Timeout
);
74 is_waiting_on_watch_
= true;
75 message_loop_runner_
= new content::MessageLoopRunner
;
76 message_loop_runner_
->Run();
77 is_waiting_on_watch_
= false;
79 return watch_notification_count_
== 0;
82 bool EndTracing(std::string
* json_trace_output
) {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
84 using namespace base::debug
;
86 if (!content::TracingController::GetInstance()->DisableRecording(
88 base::Bind(&InProcessTraceController::OnTraceDataCollected
,
89 base::Unretained(this),
90 base::Unretained(json_trace_output
))))
93 // Wait for OnEndTracingComplete() to quit the message loop.
94 message_loop_runner_
= new content::MessageLoopRunner
;
95 message_loop_runner_
->Run();
97 // Watch notifications can occur during this method's message loop run, but
98 // not after, so clear them here.
99 watch_notification_count_
= 0;
104 friend struct DefaultSingletonTraits
<InProcessTraceController
>;
106 void OnEnableTracingComplete() {
107 message_loop_runner_
->Quit();
110 void OnEndTracingComplete() {
111 message_loop_runner_
->Quit();
114 void OnTraceDataCollected(std::string
* json_trace_output
,
115 const base::FilePath
& path
) {
116 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
117 base::Bind(&InProcessTraceController::ReadTraceData
,
118 base::Unretained(this),
119 base::Unretained(json_trace_output
),
123 void ReadTraceData(std::string
* json_trace_output
,
124 const base::FilePath
& path
) {
125 json_trace_output
->clear();
126 bool ok
= base::ReadFileToString(path
, json_trace_output
);
128 base::DeleteFile(path
, false);
130 // The callers expect an array of trace events.
131 const char* preamble
= "{\"traceEvents\": ";
132 const char* trailout
= "}";
133 DCHECK(StartsWithASCII(*json_trace_output
, preamble
, true));
134 DCHECK(EndsWith(*json_trace_output
, trailout
, true));
135 json_trace_output
->erase(0, strlen(preamble
));
136 json_trace_output
->erase(json_trace_output
->end() - 1);
138 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
139 base::Bind(&InProcessTraceController::OnEndTracingComplete
,
140 base::Unretained(this)));
143 void OnWatchEventMatched() {
144 if (watch_notification_count_
== 0)
146 if (--watch_notification_count_
== 0) {
148 if (is_waiting_on_watch_
)
149 message_loop_runner_
->Quit();
154 DCHECK(is_waiting_on_watch_
);
155 message_loop_runner_
->Quit();
158 scoped_refptr
<content::MessageLoopRunner
> message_loop_runner_
;
160 base::OneShotTimer
<InProcessTraceController
> timer_
;
162 bool is_waiting_on_watch_
;
163 int watch_notification_count_
;
165 DISALLOW_COPY_AND_ASSIGN(InProcessTraceController
);
172 bool BeginTracing(const std::string
& category_patterns
) {
173 return InProcessTraceController::GetInstance()->BeginTracing(
177 bool BeginTracingWithWatch(const std::string
& category_patterns
,
178 const std::string
& category_name
,
179 const std::string
& event_name
,
180 int num_occurrences
) {
181 return InProcessTraceController::GetInstance()->BeginTracingWithWatch(
182 category_patterns
, category_name
, event_name
, num_occurrences
);
185 bool WaitForWatchEvent(base::TimeDelta timeout
) {
186 return InProcessTraceController::GetInstance()->WaitForWatchEvent(timeout
);
189 bool EndTracing(std::string
* json_trace_output
) {
190 return InProcessTraceController::GetInstance()->EndTracing(json_trace_output
);
193 } // namespace tracing