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