Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / tracing / tracing_ui.cc
blob3edcd183d951f2536ec75ce9d96d0cd47ddb8c33
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"
7 #include <set>
8 #include <string>
9 #include <vector>
11 #include "base/base64.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/command_line.h"
15 #include "base/file_util.h"
16 #include "base/format_macros.h"
17 #include "base/json/json_reader.h"
18 #include "base/json/json_writer.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_split.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/values.h"
25 #include "content/browser/tracing/grit/tracing_resources.h"
26 #include "content/browser/tracing/trace_uploader.h"
27 #include "content/browser/tracing/tracing_controller_impl.h"
28 #include "content/public/browser/browser_context.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/tracing_controller.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_ui.h"
33 #include "content/public/browser/web_ui_data_source.h"
34 #include "content/public/common/content_client.h"
35 #include "content/public/common/content_switches.h"
36 #include "content/public/common/url_constants.h"
38 namespace content {
39 namespace {
41 const char kUploadURL[] = "https://clients2.google.com/cr/staging_report";
43 void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
44 const std::set<std::string>& categorySet) {
45 scoped_ptr<base::ListValue> category_list(new base::ListValue());
46 for (std::set<std::string>::const_iterator it = categorySet.begin();
47 it != categorySet.end(); it++) {
48 category_list->AppendString(*it);
51 base::RefCountedString* res = new base::RefCountedString();
52 base::JSONWriter::Write(category_list.get(), &res->data());
53 callback.Run(res);
56 bool GetTracingOptions(const std::string& data64,
57 std::string* category_filter_string,
58 int* tracing_options) {
59 std::string data;
60 if (!base::Base64Decode(data64, &data)) {
61 LOG(ERROR) << "Options were not base64 encoded.";
62 return false;
65 scoped_ptr<base::Value> optionsRaw(base::JSONReader::Read(data));
66 if (!optionsRaw) {
67 LOG(ERROR) << "Options were not valid JSON";
68 return false;
70 base::DictionaryValue* options;
71 if (!optionsRaw->GetAsDictionary(&options)) {
72 LOG(ERROR) << "Options must be dict";
73 return false;
76 bool use_system_tracing;
77 bool use_continuous_tracing;
78 bool use_sampling;
80 bool options_ok = true;
81 options_ok &= options->GetString("categoryFilter", category_filter_string);
82 options_ok &= options->GetBoolean("useSystemTracing", &use_system_tracing);
83 options_ok &= options->GetBoolean("useContinuousTracing",
84 &use_continuous_tracing);
85 options_ok &= options->GetBoolean("useSampling", &use_sampling);
86 if (!options_ok) {
87 LOG(ERROR) << "Malformed options";
88 return false;
91 *tracing_options = 0;
92 if (use_system_tracing)
93 *tracing_options |= TracingController::ENABLE_SYSTRACE;
94 if (use_sampling)
95 *tracing_options |= TracingController::ENABLE_SAMPLING;
96 if (use_continuous_tracing)
97 *tracing_options |= TracingController::RECORD_CONTINUOUSLY;
98 return true;
101 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback);
103 bool BeginRecording(const std::string& data64,
104 const WebUIDataSource::GotDataCallback& callback) {
105 std::string category_filter_string;
106 int tracing_options = 0;
107 if (!GetTracingOptions(data64, &category_filter_string, &tracing_options))
108 return false;
110 return TracingController::GetInstance()->EnableRecording(
111 category_filter_string,
112 static_cast<TracingController::Options>(tracing_options),
113 base::Bind(&OnRecordingEnabledAck, callback));
116 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
117 base::RefCountedString* res = new base::RefCountedString();
118 callback.Run(res);
121 void OnTraceBufferPercentFullResult(
122 const WebUIDataSource::GotDataCallback& callback, float result) {
123 std::string str = base::DoubleToString(result);
124 callback.Run(base::RefCountedString::TakeString(&str));
127 void ReadRecordingResult(const WebUIDataSource::GotDataCallback& callback,
128 const base::FilePath& path) {
129 std::string tmp;
130 if (!base::ReadFileToString(path, &tmp))
131 LOG(ERROR) << "Failed to read file " << path.value();
132 base::DeleteFile(path, false);
133 callback.Run(base::RefCountedString::TakeString(&tmp));
136 void BeginReadingRecordingResult(
137 const WebUIDataSource::GotDataCallback& callback,
138 const base::FilePath& path) {
139 BrowserThread::PostTask(
140 BrowserThread::FILE, FROM_HERE,
141 base::Bind(ReadRecordingResult, callback, path));
144 void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback);
146 bool EnableMonitoring(const std::string& data64,
147 const WebUIDataSource::GotDataCallback& callback) {
148 std::string category_filter_string;
149 int tracing_options = 0;
150 if (!GetTracingOptions(data64, &category_filter_string, &tracing_options))
151 return false;
153 return TracingController::GetInstance()->EnableMonitoring(
154 category_filter_string,
155 static_cast<TracingController::Options>(tracing_options),
156 base::Bind(OnMonitoringEnabledAck, callback));
159 void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
160 base::RefCountedString* res = new base::RefCountedString();
161 callback.Run(res);
164 void OnMonitoringDisabled(const WebUIDataSource::GotDataCallback& callback) {
165 base::RefCountedString* res = new base::RefCountedString();
166 callback.Run(res);
169 void GetMonitoringStatus(const WebUIDataSource::GotDataCallback& callback) {
170 bool is_monitoring;
171 std::string category_filter;
172 TracingController::Options options;
173 TracingController::GetInstance()->GetMonitoringStatus(
174 &is_monitoring, &category_filter, &options);
176 scoped_ptr<base::DictionaryValue>
177 monitoring_options(new base::DictionaryValue());
178 monitoring_options->SetBoolean("isMonitoring", is_monitoring);
179 monitoring_options->SetString("categoryFilter", category_filter);
180 monitoring_options->SetBoolean("useSystemTracing",
181 (options & TracingController::ENABLE_SYSTRACE) != 0);
182 monitoring_options->SetBoolean("useContinuousTracing",
183 (options & TracingController::RECORD_CONTINUOUSLY) != 0);
184 monitoring_options->SetBoolean("useSampling",
185 (options & TracingController::ENABLE_SAMPLING) != 0);
187 std::string monitoring_options_json;
188 base::JSONWriter::Write(monitoring_options.get(), &monitoring_options_json);
190 base::RefCountedString* monitoring_options_base64 =
191 new base::RefCountedString();
192 base::Base64Encode(monitoring_options_json,
193 &monitoring_options_base64->data());
194 callback.Run(monitoring_options_base64);
197 void ReadMonitoringSnapshot(const WebUIDataSource::GotDataCallback& callback,
198 const base::FilePath& path) {
199 std::string tmp;
200 if (!base::ReadFileToString(path, &tmp))
201 LOG(ERROR) << "Failed to read file " << path.value();
202 base::DeleteFile(path, false);
203 callback.Run(base::RefCountedString::TakeString(&tmp));
206 void OnMonitoringSnapshotCaptured(
207 const WebUIDataSource::GotDataCallback& callback,
208 const base::FilePath& path) {
209 BrowserThread::PostTask(
210 BrowserThread::FILE, FROM_HERE,
211 base::Bind(ReadMonitoringSnapshot, callback, path));
214 bool OnBeginJSONRequest(const std::string& path,
215 const WebUIDataSource::GotDataCallback& callback) {
216 if (path == "json/categories") {
217 return TracingController::GetInstance()->GetCategories(
218 base::Bind(OnGotCategories, callback));
221 const char* beginRecordingPath = "json/begin_recording?";
222 if (StartsWithASCII(path, beginRecordingPath, true)) {
223 std::string data = path.substr(strlen(beginRecordingPath));
224 return BeginRecording(data, callback);
226 if (path == "json/get_buffer_percent_full") {
227 return TracingController::GetInstance()->GetTraceBufferPercentFull(
228 base::Bind(OnTraceBufferPercentFullResult, callback));
230 if (path == "json/end_recording") {
231 return TracingController::GetInstance()->DisableRecording(
232 base::FilePath(), base::Bind(BeginReadingRecordingResult, callback));
235 const char* enableMonitoringPath = "json/begin_monitoring?";
236 if (path.find(enableMonitoringPath) == 0) {
237 std::string data = path.substr(strlen(enableMonitoringPath));
238 return EnableMonitoring(data, callback);
240 if (path == "json/end_monitoring") {
241 return TracingController::GetInstance()->DisableMonitoring(
242 base::Bind(OnMonitoringDisabled, callback));
244 if (path == "json/capture_monitoring") {
245 TracingController::GetInstance()->CaptureMonitoringSnapshot(
246 base::FilePath(), base::Bind(OnMonitoringSnapshotCaptured, callback));
247 return true;
249 if (path == "json/get_monitoring_status") {
250 GetMonitoringStatus(callback);
251 return true;
254 LOG(ERROR) << "Unhandled request to " << path;
255 return false;
258 bool OnTracingRequest(const std::string& path,
259 const WebUIDataSource::GotDataCallback& callback) {
260 if (StartsWithASCII(path, "json/", true)) {
261 if (!OnBeginJSONRequest(path, callback)) {
262 std::string error("##ERROR##");
263 callback.Run(base::RefCountedString::TakeString(&error));
265 return true;
267 return false;
270 } // namespace
273 ////////////////////////////////////////////////////////////////////////////////
275 // TracingUI
277 ////////////////////////////////////////////////////////////////////////////////
279 TracingUI::TracingUI(WebUI* web_ui)
280 : WebUIController(web_ui),
281 weak_factory_(this) {
282 web_ui->RegisterMessageCallback(
283 "doUpload",
284 base::Bind(&TracingUI::DoUpload, base::Unretained(this)));
286 // Set up the chrome://tracing/ source.
287 BrowserContext* browser_context =
288 web_ui->GetWebContents()->GetBrowserContext();
290 WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost);
291 source->SetJsonPath("strings.js");
292 source->SetDefaultResource(IDR_TRACING_HTML);
293 source->AddResourcePath("tracing.js", IDR_TRACING_JS);
294 source->SetRequestFilter(base::Bind(OnTracingRequest));
295 WebUIDataSource::Add(browser_context, source);
296 TracingControllerImpl::GetInstance()->RegisterTracingUI(this);
299 TracingUI::~TracingUI() {
300 TracingControllerImpl::GetInstance()->UnregisterTracingUI(this);
303 void TracingUI::OnMonitoringStateChanged(bool is_monitoring) {
304 web_ui()->CallJavascriptFunction(
305 "onMonitoringStateChanged", base::FundamentalValue(is_monitoring));
308 void TracingUI::DoUpload(const base::ListValue* args) {
309 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
310 std::string upload_url = kUploadURL;
311 if (command_line.HasSwitch(switches::kTraceUploadURL)) {
312 upload_url =
313 command_line.GetSwitchValueASCII(switches::kTraceUploadURL);
315 if (!GURL(upload_url).is_valid()) {
316 upload_url.clear();
319 if (upload_url.empty()) {
320 web_ui()->CallJavascriptFunction("onUploadError",
321 base::StringValue("Upload URL empty or invalid"));
322 return;
325 std::string file_contents;
326 if (!args || args->empty() || !args->GetString(0, &file_contents)) {
327 web_ui()->CallJavascriptFunction("onUploadError",
328 base::StringValue("Missing data"));
329 return;
332 TraceUploader::UploadProgressCallback progress_callback =
333 base::Bind(&TracingUI::OnTraceUploadProgress,
334 weak_factory_.GetWeakPtr());
335 TraceUploader::UploadDoneCallback done_callback =
336 base::Bind(&TracingUI::OnTraceUploadComplete,
337 weak_factory_.GetWeakPtr());
339 #if defined(OS_WIN)
340 const char product[] = "Chrome";
341 #elif defined(OS_MACOSX)
342 const char product[] = "Chrome_Mac";
343 #elif defined(OS_LINUX)
344 const char product[] = "Chrome_Linux";
345 #elif defined(OS_ANDROID)
346 const char product[] = "Chrome_Android";
347 #elif defined(OS_CHROMEOS)
348 const char product[] = "Chrome_ChromeOS";
349 #else
350 #error Platform not supported.
351 #endif
353 // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
354 // the part before the "/".
355 std::vector<std::string> product_components;
356 base::SplitString(content::GetContentClient()->GetProduct(), '/',
357 &product_components);
358 DCHECK_EQ(2U, product_components.size());
359 std::string version;
360 if (product_components.size() == 2U) {
361 version = product_components[1];
362 } else {
363 version = "unknown";
366 BrowserContext* browser_context =
367 web_ui()->GetWebContents()->GetBrowserContext();
368 TraceUploader* uploader = new TraceUploader(
369 product, version, upload_url, browser_context->GetRequestContext());
371 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
372 &TraceUploader::DoUpload,
373 base::Unretained(uploader),
374 file_contents,
375 progress_callback,
376 done_callback));
377 // TODO(mmandlis): Add support for stopping the upload in progress.
380 void TracingUI::OnTraceUploadProgress(int64 current, int64 total) {
381 DCHECK(current <= total);
382 int percent = (current / total) * 100;
383 web_ui()->CallJavascriptFunction(
384 "onUploadProgress",
385 base::FundamentalValue(percent),
386 base::StringValue(base::StringPrintf("%" PRId64, current)),
387 base::StringValue(base::StringPrintf("%" PRId64, total)));
390 void TracingUI::OnTraceUploadComplete(bool success,
391 const std::string& report_id,
392 const std::string& error_message) {
393 if (success) {
394 web_ui()->CallJavascriptFunction("onUploadComplete",
395 base::StringValue(report_id));
396 } else {
397 web_ui()->CallJavascriptFunction("onUploadError",
398 base::StringValue(error_message));
402 } // namespace content