blob: aab652d5bf1f2dc3ae2886460b84a159fde202b0 [file] [log] [blame]
[email protected]bcb6ee23d2013-02-03 04:06:401// 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/bind.h"
10#include "base/bind_helpers.h"
11#include "base/command_line.h"
12#include "base/debug/trace_event.h"
13#include "base/file_util.h"
[email protected]9e5952e2013-05-18 09:29:0114#include "base/json/string_escape.h"
[email protected]bcb6ee23d2013-02-03 04:06:4015#include "base/memory/scoped_ptr.h"
[email protected]3ea1b182013-02-08 22:38:4116#include "base/strings/string_number_conversions.h"
[email protected]348fbaac2013-06-11 06:31:5117#include "base/strings/string_util.h"
18#include "base/strings/stringprintf.h"
[email protected]74ebfb12013-06-07 20:48:0019#include "base/strings/utf_string_conversions.h"
[email protected]bcb6ee23d2013-02-03 04:06:4020#include "base/values.h"
21#include "content/public/browser/browser_thread.h"
22#include "content/public/browser/content_browser_client.h"
23#include "content/public/browser/render_view_host.h"
24#include "content/public/browser/trace_controller.h"
25#include "content/public/browser/trace_subscriber.h"
26#include "content/public/browser/web_contents.h"
27#include "content/public/browser/web_contents_view.h"
28#include "content/public/browser/web_ui.h"
29#include "content/public/browser/web_ui_data_source.h"
30#include "content/public/browser/web_ui_message_handler.h"
31#include "content/public/common/url_constants.h"
[email protected]479bea22013-07-02 21:46:0632#include "grit/tracing_resources.h"
[email protected]bcb6ee23d2013-02-03 04:06:4033#include "ipc/ipc_channel.h"
34#include "ui/shell_dialogs/select_file_dialog.h"
35
36#if defined(OS_CHROMEOS)
37#include "chromeos/dbus/dbus_thread_manager.h"
38#include "chromeos/dbus/debug_daemon_client.h"
39#endif
40
41namespace content {
42namespace {
43
44WebUIDataSource* CreateTracingHTMLSource() {
[email protected]46ed0862013-04-14 02:47:5645 WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost);
[email protected]bcb6ee23d2013-02-03 04:06:4046
47 source->SetJsonPath("strings.js");
48 source->SetDefaultResource(IDR_TRACING_HTML);
49 source->AddResourcePath("tracing.js", IDR_TRACING_JS);
[email protected]bcb6ee23d2013-02-03 04:06:4050 return source;
51}
52
53// This class receives javascript messages from the renderer.
54// Note that the WebUI infrastructure runs on the UI thread, therefore all of
55// this class's methods are expected to run on the UI thread.
56class TracingMessageHandler
57 : public WebUIMessageHandler,
58 public ui::SelectFileDialog::Listener,
59 public base::SupportsWeakPtr<TracingMessageHandler>,
60 public TraceSubscriber {
61 public:
62 TracingMessageHandler();
63 virtual ~TracingMessageHandler();
64
65 // WebUIMessageHandler implementation.
[email protected]c3e35892013-02-12 02:08:0166 virtual void RegisterMessages() OVERRIDE;
[email protected]bcb6ee23d2013-02-03 04:06:4067
68 // SelectFileDialog::Listener implementation
[email protected]2dec8ec2013-02-07 19:20:3469 virtual void FileSelected(const base::FilePath& path,
70 int index,
[email protected]c3e35892013-02-12 02:08:0171 void* params) OVERRIDE;
72 virtual void FileSelectionCanceled(void* params) OVERRIDE;
[email protected]bcb6ee23d2013-02-03 04:06:4073
74 // TraceSubscriber implementation.
[email protected]c3e35892013-02-12 02:08:0175 virtual void OnEndTracingComplete() OVERRIDE;
[email protected]bcb6ee23d2013-02-03 04:06:4076 virtual void OnTraceDataCollected(
[email protected]c3e35892013-02-12 02:08:0177 const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE;
78 virtual void OnTraceBufferPercentFullReply(float percent_full) OVERRIDE;
[email protected]3dfd28c92013-03-24 05:36:5679 virtual void OnKnownCategoriesCollected(
80 const std::set<std::string>& known_categories) OVERRIDE;
[email protected]bcb6ee23d2013-02-03 04:06:4081
82 // Messages.
[email protected]0cd50aa2013-02-12 22:28:0183 void OnTracingControllerInitialized(const base::ListValue* list);
84 void OnBeginTracing(const base::ListValue* list);
85 void OnEndTracingAsync(const base::ListValue* list);
86 void OnBeginRequestBufferPercentFull(const base::ListValue* list);
87 void OnLoadTraceFile(const base::ListValue* list);
88 void OnSaveTraceFile(const base::ListValue* list);
[email protected]3dfd28c92013-03-24 05:36:5689 void OnGetKnownCategories(const base::ListValue* list);
[email protected]bcb6ee23d2013-02-03 04:06:4090
91 // Callbacks.
[email protected]f18491c92013-05-28 02:28:1892 void LoadTraceFileComplete(string16* file_contents,
93 const base::FilePath &path);
[email protected]bcb6ee23d2013-02-03 04:06:4094 void SaveTraceFileComplete();
95
96 private:
97 // The file dialog to select a file for loading or saving traces.
98 scoped_refptr<ui::SelectFileDialog> select_trace_file_dialog_;
99
100 // The type of the file dialog as the same one is used for loading or saving
101 // traces.
102 ui::SelectFileDialog::Type select_trace_file_dialog_type_;
103
104 // The trace data that is to be written to the file on saving.
105 scoped_ptr<std::string> trace_data_to_save_;
106
107 // True while tracing is active.
108 bool trace_enabled_;
109
110 // True while system tracing is active.
111 bool system_trace_in_progress_;
112
113 void OnEndSystemTracingAck(
114 const scoped_refptr<base::RefCountedString>& events_str_ptr);
115
116 DISALLOW_COPY_AND_ASSIGN(TracingMessageHandler);
117};
118
119// A proxy passed to the Read and Write tasks used when loading or saving trace
120// data.
121class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
122 public:
123 explicit TaskProxy(const base::WeakPtr<TracingMessageHandler>& handler)
124 : handler_(handler) {}
[email protected]f18491c92013-05-28 02:28:18125 void LoadTraceFileCompleteProxy(string16* file_contents,
126 const base::FilePath& path) {
[email protected]c679b2a82013-06-03 21:25:01127 if (handler_.get())
[email protected]f18491c92013-05-28 02:28:18128 handler_->LoadTraceFileComplete(file_contents, path);
[email protected]bcb6ee23d2013-02-03 04:06:40129 delete file_contents;
130 }
131
132 void SaveTraceFileCompleteProxy() {
[email protected]c679b2a82013-06-03 21:25:01133 if (handler_.get())
[email protected]bcb6ee23d2013-02-03 04:06:40134 handler_->SaveTraceFileComplete();
135 }
136
137 private:
138 friend class base::RefCountedThreadSafe<TaskProxy>;
139 ~TaskProxy() {}
140
141 // The message handler to call callbacks on.
142 base::WeakPtr<TracingMessageHandler> handler_;
143
144 DISALLOW_COPY_AND_ASSIGN(TaskProxy);
145};
146
147////////////////////////////////////////////////////////////////////////////////
148//
149// TracingMessageHandler
150//
151////////////////////////////////////////////////////////////////////////////////
152
153TracingMessageHandler::TracingMessageHandler()
154 : select_trace_file_dialog_type_(ui::SelectFileDialog::SELECT_NONE),
155 trace_enabled_(false),
156 system_trace_in_progress_(false) {
157}
158
159TracingMessageHandler::~TracingMessageHandler() {
[email protected]fc72bb12013-06-02 21:13:46160 if (select_trace_file_dialog_.get())
[email protected]bcb6ee23d2013-02-03 04:06:40161 select_trace_file_dialog_->ListenerDestroyed();
162
163 // If we are the current subscriber, this will result in ending tracing.
164 TraceController::GetInstance()->CancelSubscriber(this);
165
166 // Shutdown any system tracing too.
167 if (system_trace_in_progress_) {
168#if defined(OS_CHROMEOS)
169 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
170 RequestStopSystemTracing(
171 chromeos::DebugDaemonClient::EmptyStopSystemTracingCallback());
172#endif
173 }
174}
175
176void TracingMessageHandler::RegisterMessages() {
177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
178
179 web_ui()->RegisterMessageCallback("tracingControllerInitialized",
180 base::Bind(&TracingMessageHandler::OnTracingControllerInitialized,
181 base::Unretained(this)));
182 web_ui()->RegisterMessageCallback("beginTracing",
183 base::Bind(&TracingMessageHandler::OnBeginTracing,
184 base::Unretained(this)));
185 web_ui()->RegisterMessageCallback("endTracingAsync",
186 base::Bind(&TracingMessageHandler::OnEndTracingAsync,
187 base::Unretained(this)));
188 web_ui()->RegisterMessageCallback("beginRequestBufferPercentFull",
189 base::Bind(&TracingMessageHandler::OnBeginRequestBufferPercentFull,
190 base::Unretained(this)));
191 web_ui()->RegisterMessageCallback("loadTraceFile",
192 base::Bind(&TracingMessageHandler::OnLoadTraceFile,
193 base::Unretained(this)));
194 web_ui()->RegisterMessageCallback("saveTraceFile",
195 base::Bind(&TracingMessageHandler::OnSaveTraceFile,
196 base::Unretained(this)));
[email protected]3dfd28c92013-03-24 05:36:56197 web_ui()->RegisterMessageCallback("getKnownCategories",
198 base::Bind(&TracingMessageHandler::OnGetKnownCategories,
199 base::Unretained(this)));
[email protected]bcb6ee23d2013-02-03 04:06:40200}
201
202void TracingMessageHandler::OnTracingControllerInitialized(
[email protected]0cd50aa2013-02-12 22:28:01203 const base::ListValue* args) {
[email protected]bcb6ee23d2013-02-03 04:06:40204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
205
206 // Send the client info to the tracingController
207 {
[email protected]0cd50aa2013-02-12 22:28:01208 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
[email protected]bcb6ee23d2013-02-03 04:06:40209 dict->SetString("version", GetContentClient()->GetProduct());
210
211 dict->SetString("command_line",
212 CommandLine::ForCurrentProcess()->GetCommandLineString());
213
214 web_ui()->CallJavascriptFunction("tracingController.onClientInfoUpdate",
215 *dict);
216 }
217}
218
219void TracingMessageHandler::OnBeginRequestBufferPercentFull(
[email protected]0cd50aa2013-02-12 22:28:01220 const base::ListValue* list) {
[email protected]bcb6ee23d2013-02-03 04:06:40221 TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this);
222}
223
224// A callback used for asynchronously reading a file to a string. Calls the
225// TaskProxy callback when reading is complete.
[email protected]2dec8ec2013-02-07 19:20:34226void ReadTraceFileCallback(TaskProxy* proxy, const base::FilePath& path) {
[email protected]bcb6ee23d2013-02-03 04:06:40227 std::string file_contents;
228 if (!file_util::ReadFileToString(path, &file_contents))
229 return;
230
231 // We need to escape the file contents, because it will go into a javascript
232 // quoted string in TracingMessageHandler::LoadTraceFileComplete. We need to
233 // escape control characters (to have well-formed javascript statements), as
234 // well as \ and ' (the only special characters in a ''-quoted string).
235 // Do the escaping on this thread, it may take a little while for big files
236 // and we don't want to block the UI during that time. Also do the UTF-16
237 // conversion here.
238 // Note: we're using UTF-16 because we'll need to cut the string into slices
239 // to give to Javascript, and it's easier to cut than UTF-8 (since JS strings
240 // are arrays of 16-bit values, UCS-2 really, whereas we can't cut inside of a
241 // multibyte UTF-8 codepoint).
242 size_t size = file_contents.size();
243 std::string escaped_contents;
244 escaped_contents.reserve(size);
245 for (size_t i = 0; i < size; ++i) {
246 char c = file_contents[i];
247 if (c < ' ') {
248 escaped_contents += base::StringPrintf("\\u%04x", c);
249 continue;
250 }
251 if (c == '\\' || c == '\'')
252 escaped_contents.push_back('\\');
253 escaped_contents.push_back(c);
254 }
255 file_contents.clear();
256
257 scoped_ptr<string16> contents16(new string16);
258 UTF8ToUTF16(escaped_contents).swap(*contents16);
259
260 BrowserThread::PostTask(
261 BrowserThread::UI, FROM_HERE,
262 base::Bind(&TaskProxy::LoadTraceFileCompleteProxy, proxy,
[email protected]f18491c92013-05-28 02:28:18263 contents16.release(),
264 path));
[email protected]bcb6ee23d2013-02-03 04:06:40265}
266
267// A callback used for asynchronously writing a file from a string. Calls the
268// TaskProxy callback when writing is complete.
269void WriteTraceFileCallback(TaskProxy* proxy,
[email protected]2dec8ec2013-02-07 19:20:34270 const base::FilePath& path,
[email protected]bcb6ee23d2013-02-03 04:06:40271 std::string* contents) {
272 if (!file_util::WriteFile(path, contents->c_str(), contents->size()))
273 return;
274
275 BrowserThread::PostTask(
276 BrowserThread::UI, FROM_HERE,
277 base::Bind(&TaskProxy::SaveTraceFileCompleteProxy, proxy));
278}
279
280void TracingMessageHandler::FileSelected(
[email protected]2dec8ec2013-02-07 19:20:34281 const base::FilePath& path, int index, void* params) {
[email protected]bcb6ee23d2013-02-03 04:06:40282 if (select_trace_file_dialog_type_ ==
283 ui::SelectFileDialog::SELECT_OPEN_FILE) {
284 BrowserThread::PostTask(
285 BrowserThread::FILE, FROM_HERE,
286 base::Bind(&ReadTraceFileCallback,
287 make_scoped_refptr(new TaskProxy(AsWeakPtr())), path));
288 } else {
289 BrowserThread::PostTask(
290 BrowserThread::FILE, FROM_HERE,
291 base::Bind(&WriteTraceFileCallback,
292 make_scoped_refptr(new TaskProxy(AsWeakPtr())), path,
293 trace_data_to_save_.release()));
294 }
295
296 select_trace_file_dialog_ = NULL;
297}
298
299void TracingMessageHandler::FileSelectionCanceled(void* params) {
300 select_trace_file_dialog_ = NULL;
301 if (select_trace_file_dialog_type_ ==
302 ui::SelectFileDialog::SELECT_OPEN_FILE) {
303 web_ui()->CallJavascriptFunction(
304 "tracingController.onLoadTraceFileCanceled");
305 } else {
306 web_ui()->CallJavascriptFunction(
307 "tracingController.onSaveTraceFileCanceled");
308 }
309}
310
[email protected]0cd50aa2013-02-12 22:28:01311void TracingMessageHandler::OnLoadTraceFile(const base::ListValue* list) {
[email protected]bcb6ee23d2013-02-03 04:06:40312 // Only allow a single dialog at a time.
[email protected]fc72bb12013-06-02 21:13:46313 if (select_trace_file_dialog_.get())
[email protected]bcb6ee23d2013-02-03 04:06:40314 return;
315 select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
316 select_trace_file_dialog_ = ui::SelectFileDialog::Create(
317 this,
318 GetContentClient()->browser()->CreateSelectFilePolicy(
319 web_ui()->GetWebContents()));
320 select_trace_file_dialog_->SelectFile(
321 ui::SelectFileDialog::SELECT_OPEN_FILE,
322 string16(),
[email protected]2dec8ec2013-02-07 19:20:34323 base::FilePath(),
[email protected]007b3f82013-04-09 08:46:45324 NULL,
325 0,
326 base::FilePath::StringType(),
327 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
328 NULL);
[email protected]bcb6ee23d2013-02-03 04:06:40329}
330
[email protected]f18491c92013-05-28 02:28:18331void TracingMessageHandler::LoadTraceFileComplete(string16* contents,
332 const base::FilePath& path) {
[email protected]bcb6ee23d2013-02-03 04:06:40333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
334
335 // We need to pass contents to tracingController.onLoadTraceFileComplete, but
336 // that may be arbitrarily big, and IPCs messages are limited in size. So we
337 // need to cut it into pieces and rebuild the string in Javascript.
338 // |contents| has already been escaped in ReadTraceFileCallback.
339 // IPC::Channel::kMaximumMessageSize is in bytes, and we need to account for
340 // overhead.
341 const size_t kMaxSize = IPC::Channel::kMaximumMessageSize / 2 - 128;
342 string16 first_prefix = UTF8ToUTF16("window.traceData = '");
343 string16 prefix = UTF8ToUTF16("window.traceData += '");
344 string16 suffix = UTF8ToUTF16("';");
345
346 RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
347 for (size_t i = 0; i < contents->size(); i += kMaxSize) {
348 string16 javascript = i == 0 ? first_prefix : prefix;
349 javascript += contents->substr(i, kMaxSize) + suffix;
350 rvh->ExecuteJavascriptInWebFrame(string16(), javascript);
351 }
[email protected]f18491c92013-05-28 02:28:18352
353 // The CallJavascriptFunction is not used because we need to pass
354 // the first param |window.traceData| through as an un-quoted string.
[email protected]bcb6ee23d2013-02-03 04:06:40355 rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(
[email protected]f18491c92013-05-28 02:28:18356 "tracingController.onLoadTraceFileComplete(window.traceData," +
357 base::GetDoubleQuotedJson(path.value()) + ");" +
[email protected]bcb6ee23d2013-02-03 04:06:40358 "delete window.traceData;"));
359}
360
[email protected]0cd50aa2013-02-12 22:28:01361void TracingMessageHandler::OnSaveTraceFile(const base::ListValue* list) {
[email protected]bcb6ee23d2013-02-03 04:06:40362 // Only allow a single dialog at a time.
[email protected]fc72bb12013-06-02 21:13:46363 if (select_trace_file_dialog_.get())
[email protected]bcb6ee23d2013-02-03 04:06:40364 return;
365
366 DCHECK(list->GetSize() == 1);
367
368 std::string* trace_data = new std::string();
369 bool ok = list->GetString(0, trace_data);
370 DCHECK(ok);
371 trace_data_to_save_.reset(trace_data);
372
373 select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
374 select_trace_file_dialog_ = ui::SelectFileDialog::Create(
375 this,
376 GetContentClient()->browser()->CreateSelectFilePolicy(
377 web_ui()->GetWebContents()));
378 select_trace_file_dialog_->SelectFile(
379 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
380 string16(),
[email protected]2dec8ec2013-02-07 19:20:34381 base::FilePath(),
[email protected]007b3f82013-04-09 08:46:45382 NULL,
383 0,
384 base::FilePath::StringType(),
385 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
386 NULL);
[email protected]bcb6ee23d2013-02-03 04:06:40387}
388
389void TracingMessageHandler::SaveTraceFileComplete() {
390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
391 web_ui()->CallJavascriptFunction("tracingController.onSaveTraceFileComplete");
392}
393
[email protected]0cd50aa2013-02-12 22:28:01394void TracingMessageHandler::OnBeginTracing(const base::ListValue* args) {
[email protected]bcb6ee23d2013-02-03 04:06:40395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]dcc78372013-02-23 02:09:53396 DCHECK_GE(args->GetSize(), (size_t) 2);
397 DCHECK_LE(args->GetSize(), (size_t) 3);
[email protected]bcb6ee23d2013-02-03 04:06:40398
399 bool system_tracing_requested = false;
400 bool ok = args->GetBoolean(0, &system_tracing_requested);
401 DCHECK(ok);
402
403 std::string chrome_categories;
404 ok = args->GetString(1, &chrome_categories);
405 DCHECK(ok);
406
[email protected]dcc78372013-02-23 02:09:53407 base::debug::TraceLog::Options options =
408 base::debug::TraceLog::RECORD_UNTIL_FULL;
409 if (args->GetSize() >= 3) {
410 std::string options_;
411 ok = args->GetString(2, &options_);
412 DCHECK(ok);
413 options = base::debug::TraceLog::TraceOptionsFromString(options_);
414 }
415
[email protected]bcb6ee23d2013-02-03 04:06:40416 trace_enabled_ = true;
417 // TODO(jbates) This may fail, but that's OK for current use cases.
418 // Ex: Multiple about:gpu traces can not trace simultaneously.
419 // TODO(nduca) send feedback to javascript about whether or not BeginTracing
420 // was successful.
[email protected]dcc78372013-02-23 02:09:53421 TraceController::GetInstance()->BeginTracing(this, chrome_categories,
422 options);
[email protected]bcb6ee23d2013-02-03 04:06:40423
424 if (system_tracing_requested) {
425#if defined(OS_CHROMEOS)
426 DCHECK(!system_trace_in_progress_);
427 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
428 StartSystemTracing();
429 // TODO(sleffler) async, could wait for completion
430 system_trace_in_progress_ = true;
431#endif
432 }
433}
434
[email protected]0cd50aa2013-02-12 22:28:01435void TracingMessageHandler::OnEndTracingAsync(const base::ListValue* list) {
[email protected]bcb6ee23d2013-02-03 04:06:40436 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
437
[email protected]73fbaac2013-05-02 00:40:23438 // This is really us beginning to end tracing, rather than tracing being truly
439 // over. When this function yields, we expect to get some number of
440 // OnTraceDataCollected callbacks, which will append data to window.traceData.
441 // To set up for this, set window.traceData to the empty string.
442 web_ui()->GetWebContents()->GetRenderViewHost()->
443 ExecuteJavascriptInWebFrame(string16(),
444 UTF8ToUTF16("window.traceData = '';"));
445
[email protected]bcb6ee23d2013-02-03 04:06:40446 // TODO(nduca): fix javascript code to make sure trace_enabled_ is always true
447 // here. triggered a false condition by just clicking stop
448 // trace a few times when it was going slow, and maybe switching
449 // between tabs.
450 if (trace_enabled_ &&
451 !TraceController::GetInstance()->EndTracingAsync(this)) {
452 // Set to false now, since it turns out we never were the trace subscriber.
453 OnEndTracingComplete();
454 }
455}
456
457void TracingMessageHandler::OnEndTracingComplete() {
458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
459 trace_enabled_ = false;
460 if (system_trace_in_progress_) {
461 // Disable system tracing now that the local trace has shutdown.
462 // This must be done last because we potentially need to push event
463 // records into the system event log for synchronizing system event
464 // timestamps with chrome event timestamps--and since the system event
465 // log is a ring-buffer (on linux) adding them at the end is the only
466 // way we're confident we'll have them in the final result.
467 system_trace_in_progress_ = false;
468#if defined(OS_CHROMEOS)
469 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
470 RequestStopSystemTracing(
471 base::Bind(&TracingMessageHandler::OnEndSystemTracingAck,
472 base::Unretained(this)));
473 return;
474#endif
475 }
[email protected]73fbaac2013-05-02 00:40:23476
477 RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
478 rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(
479 "tracingController.onEndTracingComplete(window.traceData);"
480 "delete window.traceData;"));
[email protected]bcb6ee23d2013-02-03 04:06:40481}
482
483void TracingMessageHandler::OnEndSystemTracingAck(
484 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
485 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
486
487 web_ui()->CallJavascriptFunction(
488 "tracingController.onSystemTraceDataCollected",
[email protected]0cd50aa2013-02-12 22:28:01489 *scoped_ptr<base::Value>(new base::StringValue(events_str_ptr->data())));
[email protected]bcb6ee23d2013-02-03 04:06:40490 DCHECK(!system_trace_in_progress_);
491
492 OnEndTracingComplete();
493}
494
495void TracingMessageHandler::OnTraceDataCollected(
496 const scoped_refptr<base::RefCountedString>& trace_fragment) {
497 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
498
[email protected]9e5952e2013-05-18 09:29:01499 std::string javascript;
500 javascript.reserve(trace_fragment->size() * 2);
501 javascript.append("window.traceData += \"");
502 base::JsonDoubleQuote(trace_fragment->data(), false, &javascript);
[email protected]335ec812013-05-03 04:42:16503
[email protected]73fbaac2013-05-02 00:40:23504 // Intentionally append a , to the traceData. This technically causes all
505 // traceData that we pass back to JS to end with a comma, but that is actually
506 // something the JS side strips away anyway
[email protected]9e5952e2013-05-18 09:29:01507 javascript.append(",\";");
[email protected]bcb6ee23d2013-02-03 04:06:40508
509 web_ui()->GetWebContents()->GetRenderViewHost()->
[email protected]73fbaac2013-05-02 00:40:23510 ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(javascript));
[email protected]bcb6ee23d2013-02-03 04:06:40511}
512
513void TracingMessageHandler::OnTraceBufferPercentFullReply(float percent_full) {
514 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
515 web_ui()->CallJavascriptFunction(
516 "tracingController.onRequestBufferPercentFullComplete",
[email protected]0cd50aa2013-02-12 22:28:01517 *scoped_ptr<base::Value>(new base::FundamentalValue(percent_full)));
[email protected]bcb6ee23d2013-02-03 04:06:40518}
519
[email protected]3dfd28c92013-03-24 05:36:56520void TracingMessageHandler::OnGetKnownCategories(const base::ListValue* list) {
521 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d936677a2013-04-19 08:49:03522 if (!TraceController::GetInstance()->GetKnownCategoryGroupsAsync(this)) {
[email protected]3dfd28c92013-03-24 05:36:56523 std::set<std::string> ret;
524 OnKnownCategoriesCollected(ret);
525 }
526}
527
528void TracingMessageHandler::OnKnownCategoriesCollected(
529 const std::set<std::string>& known_categories) {
530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
531
532 scoped_ptr<base::ListValue> categories(new base::ListValue());
[email protected]ad639852013-05-28 03:15:53533 for (std::set<std::string>::const_iterator iter = known_categories.begin();
[email protected]3dfd28c92013-03-24 05:36:56534 iter != known_categories.end();
535 ++iter) {
536 categories->AppendString(*iter);
537 }
538
539 web_ui()->CallJavascriptFunction(
540 "tracingController.onKnownCategoriesCollected", *categories);
541}
542
[email protected]bcb6ee23d2013-02-03 04:06:40543} // namespace
544
545
546////////////////////////////////////////////////////////////////////////////////
547//
548// TracingUI
549//
550////////////////////////////////////////////////////////////////////////////////
551
552TracingUI::TracingUI(WebUI* web_ui) : WebUIController(web_ui) {
553 web_ui->AddMessageHandler(new TracingMessageHandler());
554
555 // Set up the chrome://tracing/ source.
556 BrowserContext* browser_context =
557 web_ui->GetWebContents()->GetBrowserContext();
558 WebUIDataSource::Add(browser_context, CreateTracingHTMLSource());
559}
560
561} // namespace content