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 "content/browser/tracing/tracing_ui.h"
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/file_util.h"
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_util.h"
18 #include "base/values.h"
19 #include "content/browser/tracing/tracing_controller_impl.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/tracing_controller.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_ui.h"
24 #include "content/public/browser/web_ui_data_source.h"
25 #include "content/public/common/url_constants.h"
26 #include "grit/tracing_resources.h"
31 void OnGotCategories(const WebUIDataSource::GotDataCallback
& callback
,
32 const std::set
<std::string
>& categorySet
) {
34 scoped_ptr
<base::ListValue
> category_list(new base::ListValue());
35 for (std::set
<std::string
>::const_iterator it
= categorySet
.begin();
36 it
!= categorySet
.end(); it
++) {
37 category_list
->AppendString(*it
);
40 base::RefCountedString
* res
= new base::RefCountedString();
41 base::JSONWriter::Write(category_list
.get(), &res
->data());
45 bool GetTracingOptions(const std::string
& data64
,
46 std::string
* category_filter_string
,
47 int* tracing_options
) {
49 if (!base::Base64Decode(data64
, &data
)) {
50 LOG(ERROR
) << "Options were not base64 encoded.";
54 scoped_ptr
<base::Value
> optionsRaw(base::JSONReader::Read(data
));
56 LOG(ERROR
) << "Options were not valid JSON";
59 base::DictionaryValue
* options
;
60 if (!optionsRaw
->GetAsDictionary(&options
)) {
61 LOG(ERROR
) << "Options must be dict";
65 bool use_system_tracing
;
66 bool use_continuous_tracing
;
69 bool options_ok
= true;
70 options_ok
&= options
->GetString("categoryFilter", category_filter_string
);
71 options_ok
&= options
->GetBoolean("useSystemTracing", &use_system_tracing
);
72 options_ok
&= options
->GetBoolean("useContinuousTracing",
73 &use_continuous_tracing
);
74 options_ok
&= options
->GetBoolean("useSampling", &use_sampling
);
76 LOG(ERROR
) << "Malformed options";
81 if (use_system_tracing
)
82 *tracing_options
|= TracingController::ENABLE_SYSTRACE
;
84 *tracing_options
|= TracingController::ENABLE_SAMPLING
;
85 if (use_continuous_tracing
)
86 *tracing_options
|= TracingController::RECORD_CONTINUOUSLY
;
90 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback
& callback
);
92 bool BeginRecording(const std::string
& data64
,
93 const WebUIDataSource::GotDataCallback
& callback
) {
94 std::string category_filter_string
;
95 int tracing_options
= 0;
96 if (!GetTracingOptions(data64
, &category_filter_string
, &tracing_options
))
99 return TracingController::GetInstance()->EnableRecording(
100 category_filter_string
,
101 static_cast<TracingController::Options
>(tracing_options
),
102 base::Bind(&OnRecordingEnabledAck
, callback
));
105 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback
& callback
) {
106 base::RefCountedString
* res
= new base::RefCountedString();
110 void OnTraceBufferPercentFullResult(
111 const WebUIDataSource::GotDataCallback
& callback
, float result
) {
112 std::string str
= base::DoubleToString(result
);
113 callback
.Run(base::RefCountedString::TakeString(&str
));
116 void ReadRecordingResult(const WebUIDataSource::GotDataCallback
& callback
,
117 const base::FilePath
& path
) {
119 if (!base::ReadFileToString(path
, &tmp
))
120 LOG(ERROR
) << "Failed to read file " << path
.value();
121 base::DeleteFile(path
, false);
122 callback
.Run(base::RefCountedString::TakeString(&tmp
));
125 void BeginReadingRecordingResult(
126 const WebUIDataSource::GotDataCallback
& callback
,
127 const base::FilePath
& path
) {
128 BrowserThread::PostTask(
129 BrowserThread::FILE, FROM_HERE
,
130 base::Bind(ReadRecordingResult
, callback
, path
));
133 void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback
& callback
);
135 bool EnableMonitoring(const std::string
& data64
,
136 const WebUIDataSource::GotDataCallback
& callback
) {
137 std::string category_filter_string
;
138 int tracing_options
= 0;
139 if (!GetTracingOptions(data64
, &category_filter_string
, &tracing_options
))
142 return TracingController::GetInstance()->EnableMonitoring(
143 category_filter_string
,
144 static_cast<TracingController::Options
>(tracing_options
),
145 base::Bind(OnMonitoringEnabledAck
, callback
));
148 void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback
& callback
) {
149 base::RefCountedString
* res
= new base::RefCountedString();
153 void OnMonitoringDisabled(const WebUIDataSource::GotDataCallback
& callback
) {
154 base::RefCountedString
* res
= new base::RefCountedString();
158 void GetMonitoringStatus(const WebUIDataSource::GotDataCallback
& callback
) {
160 std::string category_filter
;
161 TracingController::Options options
;
162 TracingController::GetInstance()->GetMonitoringStatus(
163 &is_monitoring
, &category_filter
, &options
);
165 scoped_ptr
<base::DictionaryValue
>
166 monitoring_options(new base::DictionaryValue());
167 monitoring_options
->SetBoolean("isMonitoring", is_monitoring
);
168 monitoring_options
->SetString("categoryFilter", category_filter
);
169 monitoring_options
->SetBoolean("useSystemTracing",
170 (options
& TracingController::ENABLE_SYSTRACE
) != 0);
171 monitoring_options
->SetBoolean("useContinuousTracing",
172 (options
& TracingController::RECORD_CONTINUOUSLY
) != 0);
173 monitoring_options
->SetBoolean("useSampling",
174 (options
& TracingController::ENABLE_SAMPLING
) != 0);
176 std::string monitoring_options_json
;
177 base::JSONWriter::Write(monitoring_options
.get(), &monitoring_options_json
);
179 base::RefCountedString
* monitoring_options_base64
=
180 new base::RefCountedString();
181 base::Base64Encode(monitoring_options_json
,
182 &monitoring_options_base64
->data());
183 callback
.Run(monitoring_options_base64
);
186 void ReadMonitoringSnapshot(const WebUIDataSource::GotDataCallback
& callback
,
187 const base::FilePath
& path
) {
189 if (!base::ReadFileToString(path
, &tmp
))
190 LOG(ERROR
) << "Failed to read file " << path
.value();
191 base::DeleteFile(path
, false);
192 callback
.Run(base::RefCountedString::TakeString(&tmp
));
195 void OnMonitoringSnapshotCaptured(
196 const WebUIDataSource::GotDataCallback
& callback
,
197 const base::FilePath
& path
) {
198 BrowserThread::PostTask(
199 BrowserThread::FILE, FROM_HERE
,
200 base::Bind(ReadMonitoringSnapshot
, callback
, path
));
203 bool OnBeginJSONRequest(const std::string
& path
,
204 const WebUIDataSource::GotDataCallback
& callback
) {
205 if (path
== "json/categories") {
206 return TracingController::GetInstance()->GetCategories(
207 base::Bind(OnGotCategories
, callback
));
210 const char* beginRecordingPath
= "json/begin_recording?";
211 if (StartsWithASCII(path
, beginRecordingPath
, true)) {
212 std::string data
= path
.substr(strlen(beginRecordingPath
));
213 return BeginRecording(data
, callback
);
215 if (path
== "json/get_buffer_percent_full") {
216 return TracingController::GetInstance()->GetTraceBufferPercentFull(
217 base::Bind(OnTraceBufferPercentFullResult
, callback
));
219 if (path
== "json/end_recording") {
220 return TracingController::GetInstance()->DisableRecording(
221 base::FilePath(), base::Bind(BeginReadingRecordingResult
, callback
));
224 const char* enableMonitoringPath
= "json/begin_monitoring?";
225 if (path
.find(enableMonitoringPath
) == 0) {
226 std::string data
= path
.substr(strlen(enableMonitoringPath
));
227 return EnableMonitoring(data
, callback
);
229 if (path
== "json/end_monitoring") {
230 return TracingController::GetInstance()->DisableMonitoring(
231 base::Bind(OnMonitoringDisabled
, callback
));
233 if (path
== "json/capture_monitoring") {
234 TracingController::GetInstance()->CaptureMonitoringSnapshot(
235 base::FilePath(), base::Bind(OnMonitoringSnapshotCaptured
, callback
));
238 if (path
== "json/get_monitoring_status") {
239 GetMonitoringStatus(callback
);
243 LOG(ERROR
) << "Unhandled request to " << path
;
247 bool OnTracingRequest(const std::string
& path
,
248 const WebUIDataSource::GotDataCallback
& callback
) {
249 if (StartsWithASCII(path
, "json/", true)) {
250 if (!OnBeginJSONRequest(path
, callback
)) {
251 std::string
error("##ERROR##");
252 callback
.Run(base::RefCountedString::TakeString(&error
));
262 ////////////////////////////////////////////////////////////////////////////////
266 ////////////////////////////////////////////////////////////////////////////////
268 TracingUI::TracingUI(WebUI
* web_ui
) : WebUIController(web_ui
) {
269 // Set up the chrome://tracing/ source.
270 BrowserContext
* browser_context
=
271 web_ui
->GetWebContents()->GetBrowserContext();
273 WebUIDataSource
* source
= WebUIDataSource::Create(kChromeUITracingHost
);
274 source
->SetJsonPath("strings.js");
275 source
->SetDefaultResource(IDR_TRACING_HTML
);
276 source
->AddResourcePath("tracing.js", IDR_TRACING_JS
);
277 source
->SetRequestFilter(base::Bind(OnTracingRequest
));
278 WebUIDataSource::Add(browser_context
, source
);
279 TracingControllerImpl::GetInstance()->RegisterTracingUI(this);
282 TracingUI::~TracingUI() {
283 TracingControllerImpl::GetInstance()->UnregisterTracingUI(this);
286 void TracingUI::OnMonitoringStateChanged(bool is_monitoring
) {
287 web_ui()->CallJavascriptFunction(
288 "onMonitoringStateChanged", base::FundamentalValue(is_monitoring
));
291 } // namespace content