• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/browser/tracing/grit/tracing_resources.h"
20 #include "content/browser/tracing/tracing_controller_impl.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/tracing_controller.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_ui.h"
25 #include "content/public/browser/web_ui_data_source.h"
26 #include "content/public/common/url_constants.h"
27 
28 namespace content {
29 namespace {
30 
OnGotCategories(const WebUIDataSource::GotDataCallback & callback,const std::set<std::string> & categorySet)31 void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
32                      const std::set<std::string>& categorySet) {
33 
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);
38   }
39 
40   base::RefCountedString* res = new base::RefCountedString();
41   base::JSONWriter::Write(category_list.get(), &res->data());
42   callback.Run(res);
43 }
44 
GetTracingOptions(const std::string & data64,std::string * category_filter_string,int * tracing_options)45 bool GetTracingOptions(const std::string& data64,
46                        std::string* category_filter_string,
47                        int* tracing_options) {
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   bool use_system_tracing;
66   bool use_continuous_tracing;
67   bool use_sampling;
68 
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);
75   if (!options_ok) {
76     LOG(ERROR) << "Malformed options";
77     return false;
78   }
79 
80   *tracing_options = 0;
81   if (use_system_tracing)
82     *tracing_options |= TracingController::ENABLE_SYSTRACE;
83   if (use_sampling)
84     *tracing_options |= TracingController::ENABLE_SAMPLING;
85   if (use_continuous_tracing)
86     *tracing_options |= TracingController::RECORD_CONTINUOUSLY;
87   return true;
88 }
89 
90 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback);
91 
BeginRecording(const std::string & data64,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))
97     return false;
98 
99   return TracingController::GetInstance()->EnableRecording(
100       category_filter_string,
101       static_cast<TracingController::Options>(tracing_options),
102       base::Bind(&OnRecordingEnabledAck, callback));
103 }
104 
OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback & callback)105 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
106   base::RefCountedString* res = new base::RefCountedString();
107   callback.Run(res);
108 }
109 
OnTraceBufferPercentFullResult(const WebUIDataSource::GotDataCallback & callback,float result)110 void OnTraceBufferPercentFullResult(
111     const WebUIDataSource::GotDataCallback& callback, float result) {
112   std::string str = base::DoubleToString(result);
113   callback.Run(base::RefCountedString::TakeString(&str));
114 }
115 
ReadRecordingResult(const WebUIDataSource::GotDataCallback & callback,const base::FilePath & path)116 void ReadRecordingResult(const WebUIDataSource::GotDataCallback& callback,
117                          const base::FilePath& path) {
118   std::string tmp;
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));
123 }
124 
BeginReadingRecordingResult(const WebUIDataSource::GotDataCallback & callback,const base::FilePath & path)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));
131 }
132 
133 void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback);
134 
EnableMonitoring(const std::string & data64,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))
140     return false;
141 
142   return TracingController::GetInstance()->EnableMonitoring(
143       category_filter_string,
144       static_cast<TracingController::Options>(tracing_options),
145       base::Bind(OnMonitoringEnabledAck, callback));
146 }
147 
OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback & callback)148 void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
149   base::RefCountedString* res = new base::RefCountedString();
150   callback.Run(res);
151 }
152 
OnMonitoringDisabled(const WebUIDataSource::GotDataCallback & callback)153 void OnMonitoringDisabled(const WebUIDataSource::GotDataCallback& callback) {
154   base::RefCountedString* res = new base::RefCountedString();
155   callback.Run(res);
156 }
157 
GetMonitoringStatus(const WebUIDataSource::GotDataCallback & callback)158 void GetMonitoringStatus(const WebUIDataSource::GotDataCallback& callback) {
159   bool is_monitoring;
160   std::string category_filter;
161   TracingController::Options options;
162   TracingController::GetInstance()->GetMonitoringStatus(
163       &is_monitoring, &category_filter, &options);
164 
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);
175 
176   std::string monitoring_options_json;
177   base::JSONWriter::Write(monitoring_options.get(), &monitoring_options_json);
178 
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);
184 }
185 
ReadMonitoringSnapshot(const WebUIDataSource::GotDataCallback & callback,const base::FilePath & path)186 void ReadMonitoringSnapshot(const WebUIDataSource::GotDataCallback& callback,
187                             const base::FilePath& path) {
188   std::string tmp;
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));
193 }
194 
OnMonitoringSnapshotCaptured(const WebUIDataSource::GotDataCallback & callback,const base::FilePath & path)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));
201 }
202 
OnBeginJSONRequest(const std::string & path,const WebUIDataSource::GotDataCallback & callback)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));
208   }
209 
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);
214   }
215   if (path == "json/get_buffer_percent_full") {
216     return TracingController::GetInstance()->GetTraceBufferPercentFull(
217         base::Bind(OnTraceBufferPercentFullResult, callback));
218   }
219   if (path == "json/end_recording") {
220     return TracingController::GetInstance()->DisableRecording(
221         base::FilePath(), base::Bind(BeginReadingRecordingResult, callback));
222   }
223 
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);
228   }
229   if (path == "json/end_monitoring") {
230     return TracingController::GetInstance()->DisableMonitoring(
231         base::Bind(OnMonitoringDisabled, callback));
232   }
233   if (path == "json/capture_monitoring") {
234     TracingController::GetInstance()->CaptureMonitoringSnapshot(
235         base::FilePath(), base::Bind(OnMonitoringSnapshotCaptured, callback));
236     return true;
237   }
238   if (path == "json/get_monitoring_status") {
239     GetMonitoringStatus(callback);
240     return true;
241   }
242 
243   LOG(ERROR) << "Unhandled request to " << path;
244   return false;
245 }
246 
OnTracingRequest(const std::string & path,const WebUIDataSource::GotDataCallback & callback)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));
253     }
254     return true;
255   }
256   return false;
257 }
258 
259 }  // namespace
260 
261 
262 ////////////////////////////////////////////////////////////////////////////////
263 //
264 // TracingUI
265 //
266 ////////////////////////////////////////////////////////////////////////////////
267 
TracingUI(WebUI * web_ui)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();
272 
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);
280 }
281 
~TracingUI()282 TracingUI::~TracingUI() {
283   TracingControllerImpl::GetInstance()->UnregisterTracingUI(this);
284 }
285 
OnMonitoringStateChanged(bool is_monitoring)286 void TracingUI::OnMonitoringStateChanged(bool is_monitoring) {
287   web_ui()->CallJavascriptFunction(
288       "onMonitoringStateChanged", base::FundamentalValue(is_monitoring));
289 }
290 
291 }  // namespace content
292