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