Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: content/browser/tracing/tracing_ui.cc

Issue 24355002: Overhaul tracing_ui to use XHR and new tracing_controller (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix wrong usages of RefCountedString::TakeString Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/tracing/tracing_ui.h" 5 #include "content/browser/tracing/tracing_ui.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/base64.h"
9 #include "base/bind.h" 10 #include "base/bind.h"
10 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
11 #include "base/command_line.h"
12 #include "base/debug/trace_event.h"
13 #include "base/file_util.h" 12 #include "base/file_util.h"
14 #include "base/json/string_escape.h" 13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_ptr.h"
16 #include "base/safe_numerics.h"
17 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/values.h" 18 #include "base/values.h"
22 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/content_browser_client.h" 20 #include "content/public/browser/tracing_controller.h"
24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/trace_controller.h"
26 #include "content/public/browser/trace_subscriber.h"
27 #include "content/public/browser/web_contents.h" 21 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_view.h"
29 #include "content/public/browser/web_ui.h" 22 #include "content/public/browser/web_ui.h"
30 #include "content/public/browser/web_ui_data_source.h" 23 #include "content/public/browser/web_ui_data_source.h"
31 #include "content/public/browser/web_ui_message_handler.h"
32 #include "content/public/common/url_constants.h" 24 #include "content/public/common/url_constants.h"
33 #include "grit/tracing_resources.h" 25 #include "grit/tracing_resources.h"
34 #include "ipc/ipc_channel.h"
35 #include "ui/shell_dialogs/select_file_dialog.h"
36
37 #if defined(OS_CHROMEOS)
38 #include "chromeos/dbus/dbus_thread_manager.h"
39 #include "chromeos/dbus/debug_daemon_client.h"
40 #endif
41 26
42 namespace content { 27 namespace content {
43 namespace { 28 namespace {
44 29
45 WebUIDataSource* CreateTracingHTMLSource() { 30 void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
46 WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost); 31 const std::set<std::string>& categorySet) {
47 32
48 source->SetJsonPath("strings.js"); 33 scoped_ptr<base::ListValue> category_list(new base::ListValue());
49 source->SetDefaultResource(IDR_TRACING_HTML); 34 for (std::set<std::string>::const_iterator it = categorySet.begin();
50 source->AddResourcePath("tracing.js", IDR_TRACING_JS); 35 it != categorySet.end(); it++) {
51 return source; 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);
52 } 42 }
53 43
54 // This class receives javascript messages from the renderer. 44 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback);
55 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
56 // this class's methods are expected to run on the UI thread.
57 class TracingMessageHandler
58 : public WebUIMessageHandler,
59 public ui::SelectFileDialog::Listener,
60 public base::SupportsWeakPtr<TracingMessageHandler>,
61 public TraceSubscriber {
62 public:
63 TracingMessageHandler();
64 virtual ~TracingMessageHandler();
65 45
66 // WebUIMessageHandler implementation. 46 bool OnBeginRecording(const std::string& data64,
67 virtual void RegisterMessages() OVERRIDE; 47 const WebUIDataSource::GotDataCallback& callback) {
68 48 std::string data;
69 // SelectFileDialog::Listener implementation 49 if (!base::Base64Decode(data64, &data)) {
70 virtual void FileSelected(const base::FilePath& path, 50 LOG(ERROR) << "Options were not base64 encoded.";
71 int index, 51 return false;
72 void* params) OVERRIDE;
73 virtual void FileSelectionCanceled(void* params) OVERRIDE;
74
75 // TraceSubscriber implementation.
76 virtual void OnEndTracingComplete() OVERRIDE;
77 virtual void OnTraceDataCollected(
78 const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE;
79 virtual void OnTraceBufferPercentFullReply(float percent_full) OVERRIDE;
80 virtual void OnKnownCategoriesCollected(
81 const std::set<std::string>& known_categories) OVERRIDE;
82
83 // Messages.
84 void OnTracingControllerInitialized(const base::ListValue* list);
85 void OnBeginTracing(const base::ListValue* list);
86 void OnEndTracingAsync(const base::ListValue* list);
87 void OnBeginRequestBufferPercentFull(const base::ListValue* list);
88 void OnLoadTraceFile(const base::ListValue* list);
89 void OnSaveTraceFile(const base::ListValue* list);
90 void OnGetKnownCategories(const base::ListValue* list);
91
92 // Callbacks.
93 void LoadTraceFileComplete(string16* file_contents,
94 const base::FilePath &path);
95 void SaveTraceFileComplete();
96
97 private:
98 // The file dialog to select a file for loading or saving traces.
99 scoped_refptr<ui::SelectFileDialog> select_trace_file_dialog_;
100
101 // The type of the file dialog as the same one is used for loading or saving
102 // traces.
103 ui::SelectFileDialog::Type select_trace_file_dialog_type_;
104
105 // The trace data that is to be written to the file on saving.
106 scoped_ptr<std::string> trace_data_to_save_;
107
108 // True while tracing is active.
109 bool trace_enabled_;
110
111 // True while system tracing is active.
112 bool system_trace_in_progress_;
113
114 void OnEndSystemTracingAck(
115 const scoped_refptr<base::RefCountedString>& events_str_ptr);
116
117 DISALLOW_COPY_AND_ASSIGN(TracingMessageHandler);
118 };
119
120 // A proxy passed to the Read and Write tasks used when loading or saving trace
121 // data.
122 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
123 public:
124 explicit TaskProxy(const base::WeakPtr<TracingMessageHandler>& handler)
125 : handler_(handler) {}
126 void LoadTraceFileCompleteProxy(string16* file_contents,
127 const base::FilePath& path) {
128 if (handler_.get())
129 handler_->LoadTraceFileComplete(file_contents, path);
130 delete file_contents;
131 } 52 }
132 53
133 void SaveTraceFileCompleteProxy() { 54 scoped_ptr<base::Value> optionsRaw(base::JSONReader::Read(data));
134 if (handler_.get()) 55 if (!optionsRaw) {
135 handler_->SaveTraceFileComplete(); 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;
136 } 63 }
137 64
138 private: 65 std::string category_filter_string;
139 friend class base::RefCountedThreadSafe<TaskProxy>; 66 bool use_system_tracing;
140 ~TaskProxy() {} 67 bool use_continuous_tracing;
68 bool use_sampling;
141 69
142 // The message handler to call callbacks on. 70 bool options_ok = true;
143 base::WeakPtr<TracingMessageHandler> handler_; 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 }
144 80
145 DISALLOW_COPY_AND_ASSIGN(TaskProxy); 81 int tracing_options = 0;
146 }; 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;
147 88
148 //////////////////////////////////////////////////////////////////////////////// 89 base::debug::CategoryFilter category_filter(category_filter_string);
149 // 90 return TracingController::GetInstance()->EnableRecording(
150 // TracingMessageHandler 91 category_filter,
151 // 92 static_cast<TracingController::Options>(tracing_options),
152 //////////////////////////////////////////////////////////////////////////////// 93 base::Bind(OnRecordingEnabledAck, callback));
153
154 TracingMessageHandler::TracingMessageHandler()
155 : select_trace_file_dialog_type_(ui::SelectFileDialog::SELECT_NONE),
156 trace_enabled_(false),
157 system_trace_in_progress_(false) {
158 } 94 }
159 95
160 TracingMessageHandler::~TracingMessageHandler() { 96 void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
161 if (select_trace_file_dialog_.get()) 97 base::RefCountedString* res = new base::RefCountedString();
162 select_trace_file_dialog_->ListenerDestroyed(); 98 callback.Run(res);
163
164 // If we are the current subscriber, this will result in ending tracing.
165 TraceController::GetInstance()->CancelSubscriber(this);
166
167 // Shutdown any system tracing too.
168 if (system_trace_in_progress_) {
169 #if defined(OS_CHROMEOS)
170 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
171 RequestStopSystemTracing(
172 chromeos::DebugDaemonClient::EmptyStopSystemTracingCallback());
173 #endif
174 }
175 } 99 }
176 100
177 void TracingMessageHandler::RegisterMessages() { 101 void OnTraceBufferPercentFullResult(
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 102 const WebUIDataSource::GotDataCallback& callback, float result) {
179 103 std::string str = base::DoubleToString(result);
180 web_ui()->RegisterMessageCallback("tracingControllerInitialized", 104 callback.Run(base::RefCountedString::TakeString(&str));
181 base::Bind(&TracingMessageHandler::OnTracingControllerInitialized,
182 base::Unretained(this)));
183 web_ui()->RegisterMessageCallback("beginTracing",
184 base::Bind(&TracingMessageHandler::OnBeginTracing,
185 base::Unretained(this)));
186 web_ui()->RegisterMessageCallback("endTracingAsync",
187 base::Bind(&TracingMessageHandler::OnEndTracingAsync,
188 base::Unretained(this)));
189 web_ui()->RegisterMessageCallback("beginRequestBufferPercentFull",
190 base::Bind(&TracingMessageHandler::OnBeginRequestBufferPercentFull,
191 base::Unretained(this)));
192 web_ui()->RegisterMessageCallback("loadTraceFile",
193 base::Bind(&TracingMessageHandler::OnLoadTraceFile,
194 base::Unretained(this)));
195 web_ui()->RegisterMessageCallback("saveTraceFile",
196 base::Bind(&TracingMessageHandler::OnSaveTraceFile,
197 base::Unretained(this)));
198 web_ui()->RegisterMessageCallback("getKnownCategories",
199 base::Bind(&TracingMessageHandler::OnGetKnownCategories,
200 base::Unretained(this)));
201 } 105 }
202 106
203 void TracingMessageHandler::OnTracingControllerInitialized( 107 void ReadRecordingResult(const WebUIDataSource::GotDataCallback& callback,
204 const base::ListValue* args) { 108 const base::FilePath& path) {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 109 std::string tmp;
206 110 if (!base::ReadFileToString(path, &tmp))
207 // Send the client info to the tracingController 111 LOG(ERROR) << "Failed to read file " << path.value();
208 { 112 base::DeleteFile(path, false);
209 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); 113 callback.Run(base::RefCountedString::TakeString(&tmp));
210 dict->SetString("version", GetContentClient()->GetProduct());
211
212 dict->SetString("command_line",
213 CommandLine::ForCurrentProcess()->GetCommandLineString());
214
215 web_ui()->CallJavascriptFunction("tracingController.onClientInfoUpdate",
216 *dict);
217 }
218 } 114 }
219 115
220 void TracingMessageHandler::OnBeginRequestBufferPercentFull( 116 void BeginReadingRecordingResult(
221 const base::ListValue* list) { 117 const WebUIDataSource::GotDataCallback& callback,
222 TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this); 118 const base::FilePath& path) {
119 BrowserThread::PostTask(
120 BrowserThread::FILE, FROM_HERE,
121 base::Bind(ReadRecordingResult, callback, path));
223 } 122 }
224 123
225 // A callback used for asynchronously reading a file to a string. Calls the 124 bool OnBeginRequest(const std::string& path,
226 // TaskProxy callback when reading is complete. 125 const WebUIDataSource::GotDataCallback& callback) {
227 void ReadTraceFileCallback(TaskProxy* proxy, const base::FilePath& path) { 126 if (path == "json/categories") {
228 std::string file_contents; 127 TracingController::GetInstance()->GetCategories(
229 if (!base::ReadFileToString(path, &file_contents)) 128 base::Bind(OnGotCategories, callback));
230 return; 129 return true;
231
232 // We need to escape the file contents, because it will go into a javascript
233 // quoted string in TracingMessageHandler::LoadTraceFileComplete. We need to
234 // escape control characters (to have well-formed javascript statements), as
235 // well as \ and ' (the only special characters in a ''-quoted string).
236 // Do the escaping on this thread, it may take a little while for big files
237 // and we don't want to block the UI during that time. Also do the UTF-16
238 // conversion here.
239 // Note: we're using UTF-16 because we'll need to cut the string into slices
240 // to give to Javascript, and it's easier to cut than UTF-8 (since JS strings
241 // are arrays of 16-bit values, UCS-2 really, whereas we can't cut inside of a
242 // multibyte UTF-8 codepoint).
243 size_t size = file_contents.size();
244 std::string escaped_contents;
245 escaped_contents.reserve(size);
246 for (size_t i = 0; i < size; ++i) {
247 char c = file_contents[i];
248 if (c < ' ' || c == 0x7f) {
249 escaped_contents += base::StringPrintf("\\u%04x",
250 static_cast<uint8_t>(c));
251 continue;
252 }
253 if (c == '\\' || c == '\'')
254 escaped_contents.push_back('\\');
255 escaped_contents.push_back(c);
256 } 130 }
257 file_contents.clear(); 131 const char* beginRecordingPath = "json/begin_recording?";
258 132 if (path.find(beginRecordingPath) == 0) {
259 scoped_ptr<string16> contents16(new string16); 133 std::string data = path.substr(strlen(beginRecordingPath));
260 UTF8ToUTF16(escaped_contents).swap(*contents16); 134 return OnBeginRecording(data, callback);
261
262 BrowserThread::PostTask(
263 BrowserThread::UI, FROM_HERE,
264 base::Bind(&TaskProxy::LoadTraceFileCompleteProxy, proxy,
265 contents16.release(),
266 path));
267 }
268
269 // A callback used for asynchronously writing a file from a string. Calls the
270 // TaskProxy callback when writing is complete.
271 void WriteTraceFileCallback(TaskProxy* proxy,
272 const base::FilePath& path,
273 std::string* contents) {
274 int size = base::checked_numeric_cast<int>(contents->size());
275 if (file_util::WriteFile(path, contents->c_str(), size) != size)
276 return;
277
278 BrowserThread::PostTask(
279 BrowserThread::UI, FROM_HERE,
280 base::Bind(&TaskProxy::SaveTraceFileCompleteProxy, proxy));
281 }
282
283 void TracingMessageHandler::FileSelected(
284 const base::FilePath& path, int index, void* params) {
285 if (select_trace_file_dialog_type_ ==
286 ui::SelectFileDialog::SELECT_OPEN_FILE) {
287 BrowserThread::PostTask(
288 BrowserThread::FILE, FROM_HERE,
289 base::Bind(&ReadTraceFileCallback,
290 make_scoped_refptr(new TaskProxy(AsWeakPtr())), path));
291 } else {
292 BrowserThread::PostTask(
293 BrowserThread::FILE, FROM_HERE,
294 base::Bind(&WriteTraceFileCallback,
295 make_scoped_refptr(new TaskProxy(AsWeakPtr())), path,
296 trace_data_to_save_.release()));
297 } 135 }
298 136 if (path == "json/get_buffer_percent_full") {
299 select_trace_file_dialog_ = NULL; 137 return TracingController::GetInstance()->GetTraceBufferPercentFull(
300 } 138 base::Bind(OnTraceBufferPercentFullResult, callback));
301
302 void TracingMessageHandler::FileSelectionCanceled(void* params) {
303 select_trace_file_dialog_ = NULL;
304 if (select_trace_file_dialog_type_ ==
305 ui::SelectFileDialog::SELECT_OPEN_FILE) {
306 web_ui()->CallJavascriptFunction(
307 "tracingController.onLoadTraceFileCanceled");
308 } else {
309 web_ui()->CallJavascriptFunction(
310 "tracingController.onSaveTraceFileCanceled");
311 } 139 }
312 } 140 if (path == "json/end_recording") {
313 141 return TracingController::GetInstance()->DisableRecording(
314 void TracingMessageHandler::OnLoadTraceFile(const base::ListValue* list) { 142 base::FilePath(), base::Bind(BeginReadingRecordingResult, callback));
315 // Only allow a single dialog at a time.
316 if (select_trace_file_dialog_.get())
317 return;
318 select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
319 select_trace_file_dialog_ = ui::SelectFileDialog::Create(
320 this,
321 GetContentClient()->browser()->CreateSelectFilePolicy(
322 web_ui()->GetWebContents()));
323 select_trace_file_dialog_->SelectFile(
324 ui::SelectFileDialog::SELECT_OPEN_FILE,
325 string16(),
326 base::FilePath(),
327 NULL,
328 0,
329 base::FilePath::StringType(),
330 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
331 NULL);
332 }
333
334 void TracingMessageHandler::LoadTraceFileComplete(string16* contents,
335 const base::FilePath& path) {
336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
337
338 // We need to pass contents to tracingController.onLoadTraceFileComplete, but
339 // that may be arbitrarily big, and IPCs messages are limited in size. So we
340 // need to cut it into pieces and rebuild the string in Javascript.
341 // |contents| has already been escaped in ReadTraceFileCallback, so we need to
342 // avoid splitting escape sequences (e.g., \' or \u1234) to keep the data
343 // intact. IPC::Channel::kMaximumMessageSize is in bytes, and we need to
344 // account for overhead.
345 const size_t kMaxSize = IPC::Channel::kMaximumMessageSize / 2 - 128;
346 const size_t kControlCharEscapeSequenceSize = 5;
347 string16 first_prefix = UTF8ToUTF16("window.traceData = '");
348 string16 prefix = UTF8ToUTF16("window.traceData += '");
349 string16 suffix = UTF8ToUTF16("';");
350
351 RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
352
353 size_t flush_offset = 0;
354 size_t token_start = 0;
355 while (flush_offset < contents->size()) {
356 size_t token_end = token_start;
357 if ((*contents)[token_end] == '\\') {
358 token_end++;
359 DCHECK(token_end < contents->size());
360 if (token_end < contents->size() && (*contents)[token_end] == 'u') {
361 token_end += kControlCharEscapeSequenceSize;
362 } else {
363 token_end++;
364 }
365 } else {
366 token_end++;
367 }
368 token_end = std::min(contents->size(), token_end);
369 size_t token_size = token_end - token_start;
370 size_t flush_size = token_start - flush_offset;
371 if (token_end == contents->size()) {
372 flush_size = contents->size() - flush_offset;
373 } else if (flush_size + token_size < kMaxSize) {
374 token_start += token_size;
375 continue;
376 }
377 string16 javascript = flush_offset == 0 ? first_prefix : prefix;
378 javascript += contents->substr(flush_offset, flush_size) + suffix;
379 rvh->ExecuteJavascriptInWebFrame(string16(), javascript);
380 flush_offset += flush_size;
381 } 143 }
382 144 if (StartsWithASCII(path, "json/", true))
383 // The CallJavascriptFunction is not used because we need to pass 145 LOG(ERROR) << "Unhandled request to " << path;
384 // the first param |window.traceData| through as an un-quoted string. 146 return false;
385 rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(
386 "tracingController.onLoadTraceFileComplete(window.traceData," +
387 base::GetDoubleQuotedJson(path.value()) + ");" +
388 "delete window.traceData;"));
389 }
390
391 void TracingMessageHandler::OnSaveTraceFile(const base::ListValue* list) {
392 // Only allow a single dialog at a time.
393 if (select_trace_file_dialog_.get())
394 return;
395
396 DCHECK_EQ(1U, list->GetSize());
397
398 std::string* trace_data = new std::string();
399 bool ok = list->GetString(0, trace_data);
400 DCHECK(ok);
401 trace_data_to_save_.reset(trace_data);
402
403 select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
404 select_trace_file_dialog_ = ui::SelectFileDialog::Create(
405 this,
406 GetContentClient()->browser()->CreateSelectFilePolicy(
407 web_ui()->GetWebContents()));
408 select_trace_file_dialog_->SelectFile(
409 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
410 string16(),
411 base::FilePath(),
412 NULL,
413 0,
414 base::FilePath::StringType(),
415 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
416 NULL);
417 }
418
419 void TracingMessageHandler::SaveTraceFileComplete() {
420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
421 web_ui()->CallJavascriptFunction("tracingController.onSaveTraceFileComplete");
422 }
423
424 void TracingMessageHandler::OnBeginTracing(const base::ListValue* args) {
425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
426 DCHECK_GE(args->GetSize(), (size_t) 2);
427 DCHECK_LE(args->GetSize(), (size_t) 3);
428
429 bool system_tracing_requested = false;
430 bool ok = args->GetBoolean(0, &system_tracing_requested);
431 DCHECK(ok);
432
433 std::string chrome_categories;
434 ok = args->GetString(1, &chrome_categories);
435 DCHECK(ok);
436
437 base::debug::TraceLog::Options options =
438 base::debug::TraceLog::RECORD_UNTIL_FULL;
439 if (args->GetSize() >= 3) {
440 std::string options_;
441 ok = args->GetString(2, &options_);
442 DCHECK(ok);
443 options = base::debug::TraceLog::TraceOptionsFromString(options_);
444 }
445
446 trace_enabled_ = true;
447 // TODO(jbates) This may fail, but that's OK for current use cases.
448 // Ex: Multiple about:gpu traces can not trace simultaneously.
449 // TODO(nduca) send feedback to javascript about whether or not BeginTracing
450 // was successful.
451 TraceController::GetInstance()->BeginTracing(this, chrome_categories,
452 options);
453
454 if (system_tracing_requested) {
455 #if defined(OS_CHROMEOS)
456 DCHECK(!system_trace_in_progress_);
457 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
458 StartSystemTracing();
459 // TODO(sleffler) async, could wait for completion
460 system_trace_in_progress_ = true;
461 #endif
462 }
463 }
464
465 void TracingMessageHandler::OnEndTracingAsync(const base::ListValue* list) {
466 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
467
468 // This is really us beginning to end tracing, rather than tracing being truly
469 // over. When this function yields, we expect to get some number of
470 // OnTraceDataCollected callbacks, which will append data to window.traceData.
471 // To set up for this, set window.traceData to the empty string.
472 web_ui()->GetWebContents()->GetRenderViewHost()->
473 ExecuteJavascriptInWebFrame(string16(),
474 UTF8ToUTF16("window.traceData = '';"));
475
476 // TODO(nduca): fix javascript code to make sure trace_enabled_ is always true
477 // here. triggered a false condition by just clicking stop
478 // trace a few times when it was going slow, and maybe switching
479 // between tabs.
480 if (trace_enabled_ &&
481 !TraceController::GetInstance()->EndTracingAsync(this)) {
482 // Set to false now, since it turns out we never were the trace subscriber.
483 OnEndTracingComplete();
484 }
485 }
486
487 void TracingMessageHandler::OnEndTracingComplete() {
488 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
489 trace_enabled_ = false;
490 if (system_trace_in_progress_) {
491 // Disable system tracing now that the local trace has shutdown.
492 // This must be done last because we potentially need to push event
493 // records into the system event log for synchronizing system event
494 // timestamps with chrome event timestamps--and since the system event
495 // log is a ring-buffer (on linux) adding them at the end is the only
496 // way we're confident we'll have them in the final result.
497 system_trace_in_progress_ = false;
498 #if defined(OS_CHROMEOS)
499 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
500 RequestStopSystemTracing(
501 base::Bind(&TracingMessageHandler::OnEndSystemTracingAck,
502 base::Unretained(this)));
503 return;
504 #endif
505 }
506
507 RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
508 rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(
509 "tracingController.onEndTracingComplete(window.traceData);"
510 "delete window.traceData;"));
511 }
512
513 void TracingMessageHandler::OnEndSystemTracingAck(
514 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
516
517 web_ui()->CallJavascriptFunction(
518 "tracingController.onSystemTraceDataCollected",
519 *scoped_ptr<base::Value>(new base::StringValue(events_str_ptr->data())));
520 DCHECK(!system_trace_in_progress_);
521
522 OnEndTracingComplete();
523 }
524
525 void TracingMessageHandler::OnTraceDataCollected(
526 const scoped_refptr<base::RefCountedString>& trace_fragment) {
527 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
528
529 std::string javascript;
530 javascript.reserve(trace_fragment->size() * 2);
531 javascript.append("window.traceData += \"");
532 base::JsonDoubleQuote(trace_fragment->data(), false, &javascript);
533
534 // Intentionally append a , to the traceData. This technically causes all
535 // traceData that we pass back to JS to end with a comma, but that is actually
536 // something the JS side strips away anyway
537 javascript.append(",\";");
538
539 web_ui()->GetWebContents()->GetRenderViewHost()->
540 ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(javascript));
541 }
542
543 void TracingMessageHandler::OnTraceBufferPercentFullReply(float percent_full) {
544 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
545 web_ui()->CallJavascriptFunction(
546 "tracingController.onRequestBufferPercentFullComplete",
547 *scoped_ptr<base::Value>(new base::FundamentalValue(percent_full)));
548 }
549
550 void TracingMessageHandler::OnGetKnownCategories(const base::ListValue* list) {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
552 if (!TraceController::GetInstance()->GetKnownCategoryGroupsAsync(this)) {
553 std::set<std::string> ret;
554 OnKnownCategoriesCollected(ret);
555 }
556 }
557
558 void TracingMessageHandler::OnKnownCategoriesCollected(
559 const std::set<std::string>& known_categories) {
560 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
561
562 scoped_ptr<base::ListValue> categories(new base::ListValue());
563 for (std::set<std::string>::const_iterator iter = known_categories.begin();
564 iter != known_categories.end();
565 ++iter) {
566 categories->AppendString(*iter);
567 }
568
569 web_ui()->CallJavascriptFunction(
570 "tracingController.onKnownCategoriesCollected", *categories);
571 } 147 }
572 148
573 } // namespace 149 } // namespace
574 150
575 151
576 //////////////////////////////////////////////////////////////////////////////// 152 ////////////////////////////////////////////////////////////////////////////////
577 // 153 //
578 // TracingUI 154 // TracingUI
579 // 155 //
580 //////////////////////////////////////////////////////////////////////////////// 156 ////////////////////////////////////////////////////////////////////////////////
581 157
582 TracingUI::TracingUI(WebUI* web_ui) : WebUIController(web_ui) { 158 TracingUI::TracingUI(WebUI* web_ui) : WebUIController(web_ui) {
583 web_ui->AddMessageHandler(new TracingMessageHandler());
584
585 // Set up the chrome://tracing/ source. 159 // Set up the chrome://tracing/ source.
586 BrowserContext* browser_context = 160 BrowserContext* browser_context =
587 web_ui->GetWebContents()->GetBrowserContext(); 161 web_ui->GetWebContents()->GetBrowserContext();
588 WebUIDataSource::Add(browser_context, CreateTracingHTMLSource()); 162
163 WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost);
164 source->SetJsonPath("strings.js");
165 source->SetDefaultResource(IDR_TRACING_HTML);
166 source->AddResourcePath("tracing.js", IDR_TRACING_JS);
167 source->SetRequestFilter(base::Bind(OnBeginRequest));
168 WebUIDataSource::Add(browser_context, source);
589 } 169 }
590 170
591 } // namespace content 171 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/tracing/tracing_controller_impl.cc ('k') | content/public/browser/tracing_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698