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 "content/browser/tracing/tracing_ui.h" 6 7 #include <string> 8 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/public/browser/browser_thread.h" 20 #include "content/public/browser/tracing_controller.h" 21 #include "content/public/browser/web_contents.h" 22 #include "content/public/browser/web_ui.h" 23 #include "content/public/browser/web_ui_data_source.h" 24 #include "content/public/common/url_constants.h" 25 #include "grit/tracing_resources.h" 26 27 namespace content { 28 namespace { 29 30 void OnGotCategories(const WebUIDataSource::GotDataCallback& callback, 31 const std::set<std::string>& categorySet) { 32 33 scoped_ptr<base::ListValue> category_list(new base::ListValue()); 34 for (std::set<std::string>::const_iterator it = categorySet.begin(); 35 it != categorySet.end(); it++) { 36 category_list->AppendString(*it); 37 } 38 39 base::RefCountedString* res = new base::RefCountedString(); 40 base::JSONWriter::Write(category_list.get(), &res->data()); 41 callback.Run(res); 42 } 43 44 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback); 45 46 bool OnBeginRecording(const std::string& data64, 47 const WebUIDataSource::GotDataCallback& callback) { 48 std::string data; 49 if (!base::Base64Decode(data64, &data)) { 50 LOG(ERROR) << "Options were not base64 encoded."; 51 return false; 52 } 53 54 scoped_ptr<base::Value> optionsRaw(base::JSONReader::Read(data)); 55 if (!optionsRaw) { 56 LOG(ERROR) << "Options were not valid JSON"; 57 return false; 58 } 59 base::DictionaryValue* options; 60 if (!optionsRaw->GetAsDictionary(&options)) { 61 LOG(ERROR) << "Options must be dict"; 62 return false; 63 } 64 65 std::string category_filter_string; 66 bool use_system_tracing; 67 bool use_continuous_tracing; 68 bool use_sampling; 69 70 bool options_ok = true; 71 options_ok &= options->GetString("categoryFilter", &category_filter_string); 72 options_ok &= options->GetBoolean("useSystemTracing", &use_system_tracing); 73 options_ok &= options->GetBoolean("useContinuousTracing", 74 &use_continuous_tracing); 75 options_ok &= options->GetBoolean("useSampling", &use_sampling); 76 if (!options_ok) { 77 LOG(ERROR) << "Malformed options"; 78 return false; 79 } 80 81 int tracing_options = 0; 82 if (use_system_tracing) 83 tracing_options |= TracingController::ENABLE_SYSTRACE; 84 if (use_sampling) 85 tracing_options |= TracingController::ENABLE_SAMPLING; 86 if (use_continuous_tracing) 87 tracing_options |= TracingController::RECORD_CONTINUOUSLY; 88 89 return TracingController::GetInstance()->EnableRecording( 90 category_filter_string, 91 static_cast<TracingController::Options>(tracing_options), 92 base::Bind(&OnRecordingEnabledAck, callback)); 93 } 94 95 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback) { 96 base::RefCountedString* res = new base::RefCountedString(); 97 callback.Run(res); 98 } 99 100 void OnTraceBufferPercentFullResult( 101 const WebUIDataSource::GotDataCallback& callback, float result) { 102 std::string str = base::DoubleToString(result); 103 callback.Run(base::RefCountedString::TakeString(&str)); 104 } 105 106 void ReadRecordingResult(const WebUIDataSource::GotDataCallback& callback, 107 const base::FilePath& path) { 108 std::string tmp; 109 if (!base::ReadFileToString(path, &tmp)) 110 LOG(ERROR) << "Failed to read file " << path.value(); 111 base::DeleteFile(path, false); 112 callback.Run(base::RefCountedString::TakeString(&tmp)); 113 } 114 115 void BeginReadingRecordingResult( 116 const WebUIDataSource::GotDataCallback& callback, 117 const base::FilePath& path) { 118 BrowserThread::PostTask( 119 BrowserThread::FILE, FROM_HERE, 120 base::Bind(ReadRecordingResult, callback, path)); 121 } 122 123 bool OnBeginRequest(const std::string& path, 124 const WebUIDataSource::GotDataCallback& callback) { 125 if (path == "json/categories") { 126 TracingController::GetInstance()->GetCategories( 127 base::Bind(OnGotCategories, callback)); 128 return true; 129 } 130 const char* beginRecordingPath = "json/begin_recording?"; 131 if (path.find(beginRecordingPath) == 0) { 132 std::string data = path.substr(strlen(beginRecordingPath)); 133 return OnBeginRecording(data, callback); 134 } 135 if (path == "json/get_buffer_percent_full") { 136 return TracingController::GetInstance()->GetTraceBufferPercentFull( 137 base::Bind(OnTraceBufferPercentFullResult, callback)); 138 } 139 if (path == "json/end_recording") { 140 return TracingController::GetInstance()->DisableRecording( 141 base::FilePath(), base::Bind(BeginReadingRecordingResult, callback)); 142 } 143 if (StartsWithASCII(path, "json/", true)) 144 LOG(ERROR) << "Unhandled request to " << path; 145 return false; 146 } 147 148 } // namespace 149 150 151 //////////////////////////////////////////////////////////////////////////////// 152 // 153 // TracingUI 154 // 155 //////////////////////////////////////////////////////////////////////////////// 156 157 TracingUI::TracingUI(WebUI* web_ui) : WebUIController(web_ui) { 158 // Set up the chrome://tracing/ source. 159 BrowserContext* browser_context = 160 web_ui->GetWebContents()->GetBrowserContext(); 161 162 WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost); 163 source->SetJsonPath("strings.js"); 164 source->SetDefaultResource(IDR_TRACING_HTML); 165 source->AddResourcePath("tracing.js", IDR_TRACING_JS); 166 source->SetRequestFilter(base::Bind(OnBeginRequest)); 167 WebUIDataSource::Add(browser_context, source); 168 } 169 170 } // namespace content 171