blob: 15bd2cf2590ad4e77510067103a33c731bcc1a73 [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]fc006cac2013-09-17 22:43:3116#include "base/safe_numerics.h"
[email protected]3ea1b182013-02-08 22:38:4117#include "base/strings/string_number_conversions.h"
[email protected]348fbaac2013-06-11 06:31:5118#include "base/strings/string_util.h"
19#include "base/strings/stringprintf.h"
[email protected]74ebfb12013-06-07 20:48:0020#include "base/strings/utf_string_conversions.h"
[email protected]bcb6ee23d2013-02-03 04:06:4021#include "base/values.h"
22#include "content/public/browser/browser_thread.h"
23#include "content/public/browser/content_browser_client.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"
28#include "content/public/browser/web_contents_view.h"
29#include "content/public/browser/web_ui.h"
30#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"
[email protected]479bea22013-07-02 21:46:0633#include "grit/tracing_resources.h"
[email protected]bcb6ee23d2013-02-03 04:06:4034#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
42namespace content {
43namespace {
44
45WebUIDataSource* CreateTracingHTMLSource() {
[email protected]46ed0862013-04-14 02:47:5646 WebUIDataSource* source = WebUIDataSource::Create(kChromeUITracingHost);
[email protected]bcb6ee23d2013-02-03 04:06:4047
48 source->SetJsonPath("strings.js");
49 source->SetDefaultResource(IDR_TRACING_HTML);
50 source->AddResourcePath("tracing.js", IDR_TRACING_JS);
[email protected]bcb6ee23d2013-02-03 04:06:4051 return source;
52}
53
54// This class receives javascript messages from the renderer.
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.
57class 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
66 // WebUIMessageHandler implementation.
[email protected]c3e35892013-02-12 02:08:0167 virtual void RegisterMessages() OVERRIDE;
[email protected]bcb6ee23d2013-02-03 04:06:4068
69 // SelectFileDialog::Listener implementation
[email protected]2dec8ec2013-02-07 19:20:3470 virtual void FileSelected(const base::FilePath& path,
71 int index,
[email protected]c3e35892013-02-12 02:08:0172 void* params) OVERRIDE;
73 virtual void FileSelectionCanceled(void* params) OVERRIDE;
[email protected]bcb6ee23d2013-02-03 04:06:4074
75 // TraceSubscriber implementation.
[email protected]c3e35892013-02-12 02:08:0176 virtual void OnEndTracingComplete() OVERRIDE;
[email protected]bcb6ee23d2013-02-03 04:06:4077 virtual void OnTraceDataCollected(
[email protected]c3e35892013-02-12 02:08:0178 const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE;
79 virtual void OnTraceBufferPercentFullReply(float percent_full) OVERRIDE;
[email protected]3dfd28c92013-03-24 05:36:5680 virtual void OnKnownCategoriesCollected(
81 const std::set<std::string>& known_categories) OVERRIDE;
[email protected]bcb6ee23d2013-02-03 04:06:4082
83 // Messages.
[email protected]0cd50aa2013-02-12 22:28:0184 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);
[email protected]3dfd28c92013-03-24 05:36:5690 void OnGetKnownCategories(const base::ListValue* list);
[email protected]bcb6ee23d2013-02-03 04:06:4091
92 // Callbacks.
[email protected]f18491c92013-05-28 02:28:1893 void LoadTraceFileComplete(string16* file_contents,
94 const base::FilePath &path);
[email protected]bcb6ee23d2013-02-03 04:06:4095 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.
122class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
123 public:
124 explicit TaskProxy(const base::WeakPtr<TracingMessageHandler>& handler)
125 : handler_(handler) {}
[email protected]f18491c92013-05-28 02:28:18126 void LoadTraceFileCompleteProxy(string16* file_contents,
127 const base::FilePath& path) {
[email protected]c679b2a82013-06-03 21:25:01128 if (handler_.get())
[email protected]f18491c92013-05-28 02:28:18129 handler_->LoadTraceFileComplete(file_contents, path);
[email protected]bcb6ee23d2013-02-03 04:06:40130 delete file_contents;
131 }
132
133 void SaveTraceFileCompleteProxy() {
[email protected]c679b2a82013-06-03 21:25:01134 if (handler_.get())
[email protected]bcb6ee23d2013-02-03 04:06:40135 handler_->SaveTraceFileComplete();
136 }
137
138 private:
139 friend class base::RefCountedThreadSafe<TaskProxy>;
140 ~TaskProxy() {}
141
142 // The message handler to call callbacks on.
143 base::WeakPtr<TracingMessageHandler> handler_;
144
145 DISALLOW_COPY_AND_ASSIGN(TaskProxy);
146};
147
148////////////////////////////////////////////////////////////////////////////////
149//
150// TracingMessageHandler
151//
152////////////////////////////////////////////////////////////////////////////////
153
154TracingMessageHandler::TracingMessageHandler()
155 : select_trace_file_dialog_type_(ui::SelectFileDialog::SELECT_NONE),
156 trace_enabled_(false),
157 system_trace_in_progress_(false) {
158}
159
160TracingMessageHandler::~TracingMessageHandler() {
[email protected]fc72bb12013-06-02 21:13:46161 if (select_trace_file_dialog_.get())
[email protected]bcb6ee23d2013-02-03 04:06:40162 select_trace_file_dialog_->ListenerDestroyed();
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}
176
177void TracingMessageHandler::RegisterMessages() {
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
179
180 web_ui()->RegisterMessageCallback("tracingControllerInitialized",
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)));
[email protected]3dfd28c92013-03-24 05:36:56198 web_ui()->RegisterMessageCallback("getKnownCategories",
199 base::Bind(&TracingMessageHandler::OnGetKnownCategories,
200 base::Unretained(this)));
[email protected]bcb6ee23d2013-02-03 04:06:40201}
202
203void TracingMessageHandler::OnTracingControllerInitialized(
[email protected]0cd50aa2013-02-12 22:28:01204 const base::ListValue* args) {
[email protected]bcb6ee23d2013-02-03 04:06:40205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
206
207 // Send the client info to the tracingController
208 {
[email protected]0cd50aa2013-02-12 22:28:01209 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
[email protected]bcb6ee23d2013-02-03 04:06:40210 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}
219
220void TracingMessageHandler::OnBeginRequestBufferPercentFull(
[email protected]0cd50aa2013-02-12 22:28:01221 const base::ListValue* list) {
[email protected]bcb6ee23d2013-02-03 04:06:40222 TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this);
223}
224
225// A callback used for asynchronously reading a file to a string. Calls the
226// TaskProxy callback when reading is complete.
[email protected]2dec8ec2013-02-07 19:20:34227void ReadTraceFileCallback(TaskProxy* proxy, const base::FilePath& path) {
[email protected]bcb6ee23d2013-02-03 04:06:40228 std::string file_contents;
[email protected]82f84b92013-08-30 18:23:50229 if (!base::ReadFileToString(path, &file_contents))
[email protected]bcb6ee23d2013-02-03 04:06:40230 return;
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 < ' ') {
249 escaped_contents += base::StringPrintf("\\u%04x", c);
250 continue;
251 }
252 if (c == '\\' || c == '\'')
253 escaped_contents.push_back('\\');
254 escaped_contents.push_back(c);
255 }
256 file_contents.clear();
257
258 scoped_ptr<string16> contents16(new string16);
259 UTF8ToUTF16(escaped_contents).swap(*contents16);
260
261 BrowserThread::PostTask(
262 BrowserThread::UI, FROM_HERE,
263 base::Bind(&TaskProxy::LoadTraceFileCompleteProxy, proxy,
[email protected]f18491c92013-05-28 02:28:18264 contents16.release(),
265 path));
[email protected]bcb6ee23d2013-02-03 04:06:40266}
267
268// A callback used for asynchronously writing a file from a string. Calls the
269// TaskProxy callback when writing is complete.
270void WriteTraceFileCallback(TaskProxy* proxy,
[email protected]2dec8ec2013-02-07 19:20:34271 const base::FilePath& path,
[email protected]bcb6ee23d2013-02-03 04:06:40272 std::string* contents) {
[email protected]fc006cac2013-09-17 22:43:31273 int size = base::checked_numeric_cast<int>(contents->size());
274 if (file_util::WriteFile(path, contents->c_str(), size) != size)
[email protected]bcb6ee23d2013-02-03 04:06:40275 return;
276
277 BrowserThread::PostTask(
278 BrowserThread::UI, FROM_HERE,
279 base::Bind(&TaskProxy::SaveTraceFileCompleteProxy, proxy));
280}
281
282void TracingMessageHandler::FileSelected(
[email protected]2dec8ec2013-02-07 19:20:34283 const base::FilePath& path, int index, void* params) {
[email protected]bcb6ee23d2013-02-03 04:06:40284 if (select_trace_file_dialog_type_ ==
285 ui::SelectFileDialog::SELECT_OPEN_FILE) {
286 BrowserThread::PostTask(
287 BrowserThread::FILE, FROM_HERE,
288 base::Bind(&ReadTraceFileCallback,
289 make_scoped_refptr(new TaskProxy(AsWeakPtr())), path));
290 } else {
291 BrowserThread::PostTask(
292 BrowserThread::FILE, FROM_HERE,
293 base::Bind(&WriteTraceFileCallback,
294 make_scoped_refptr(new TaskProxy(AsWeakPtr())), path,
295 trace_data_to_save_.release()));
296 }
297
298 select_trace_file_dialog_ = NULL;
299}
300
301void TracingMessageHandler::FileSelectionCanceled(void* params) {
302 select_trace_file_dialog_ = NULL;
303 if (select_trace_file_dialog_type_ ==
304 ui::SelectFileDialog::SELECT_OPEN_FILE) {
305 web_ui()->CallJavascriptFunction(
306 "tracingController.onLoadTraceFileCanceled");
307 } else {
308 web_ui()->CallJavascriptFunction(
309 "tracingController.onSaveTraceFileCanceled");
310 }
311}
312
[email protected]0cd50aa2013-02-12 22:28:01313void TracingMessageHandler::OnLoadTraceFile(const base::ListValue* list) {
[email protected]bcb6ee23d2013-02-03 04:06:40314 // Only allow a single dialog at a time.
[email protected]fc72bb12013-06-02 21:13:46315 if (select_trace_file_dialog_.get())
[email protected]bcb6ee23d2013-02-03 04:06:40316 return;
317 select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
318 select_trace_file_dialog_ = ui::SelectFileDialog::Create(
319 this,
320 GetContentClient()->browser()->CreateSelectFilePolicy(
321 web_ui()->GetWebContents()));
322 select_trace_file_dialog_->SelectFile(
323 ui::SelectFileDialog::SELECT_OPEN_FILE,
324 string16(),
[email protected]2dec8ec2013-02-07 19:20:34325 base::FilePath(),
[email protected]007b3f82013-04-09 08:46:45326 NULL,
327 0,
328 base::FilePath::StringType(),
329 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
330 NULL);
[email protected]bcb6ee23d2013-02-03 04:06:40331}
332
[email protected]f18491c92013-05-28 02:28:18333void TracingMessageHandler::LoadTraceFileComplete(string16* contents,
334 const base::FilePath& path) {
[email protected]bcb6ee23d2013-02-03 04:06:40335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
336
337 // We need to pass contents to tracingController.onLoadTraceFileComplete, but
338 // that may be arbitrarily big, and IPCs messages are limited in size. So we
339 // need to cut it into pieces and rebuild the string in Javascript.
340 // |contents| has already been escaped in ReadTraceFileCallback.
341 // IPC::Channel::kMaximumMessageSize is in bytes, and we need to account for
342 // overhead.
343 const size_t kMaxSize = IPC::Channel::kMaximumMessageSize / 2 - 128;
344 string16 first_prefix = UTF8ToUTF16("window.traceData = '");
345 string16 prefix = UTF8ToUTF16("window.traceData += '");
346 string16 suffix = UTF8ToUTF16("';");
347
348 RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
349 for (size_t i = 0; i < contents->size(); i += kMaxSize) {
350 string16 javascript = i == 0 ? first_prefix : prefix;
351 javascript += contents->substr(i, kMaxSize) + suffix;
352 rvh->ExecuteJavascriptInWebFrame(string16(), javascript);
353 }
[email protected]f18491c92013-05-28 02:28:18354
355 // The CallJavascriptFunction is not used because we need to pass
356 // the first param |window.traceData| through as an un-quoted string.
[email protected]bcb6ee23d2013-02-03 04:06:40357 rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(
[email protected]f18491c92013-05-28 02:28:18358 "tracingController.onLoadTraceFileComplete(window.traceData," +
359 base::GetDoubleQuotedJson(path.value()) + ");" +
[email protected]bcb6ee23d2013-02-03 04:06:40360 "delete window.traceData;"));
361}
362
[email protected]0cd50aa2013-02-12 22:28:01363void TracingMessageHandler::OnSaveTraceFile(const base::ListValue* list) {
[email protected]bcb6ee23d2013-02-03 04:06:40364 // Only allow a single dialog at a time.
[email protected]fc72bb12013-06-02 21:13:46365 if (select_trace_file_dialog_.get())
[email protected]bcb6ee23d2013-02-03 04:06:40366 return;
367
[email protected]fc006cac2013-09-17 22:43:31368 DCHECK_EQ(1U, list->GetSize());
[email protected]bcb6ee23d2013-02-03 04:06:40369
370 std::string* trace_data = new std::string();
371 bool ok = list->GetString(0, trace_data);
372 DCHECK(ok);
373 trace_data_to_save_.reset(trace_data);
374
375 select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
376 select_trace_file_dialog_ = ui::SelectFileDialog::Create(
377 this,
378 GetContentClient()->browser()->CreateSelectFilePolicy(
379 web_ui()->GetWebContents()));
380 select_trace_file_dialog_->SelectFile(
381 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
382 string16(),
[email protected]2dec8ec2013-02-07 19:20:34383 base::FilePath(),
[email protected]007b3f82013-04-09 08:46:45384 NULL,
385 0,
386 base::FilePath::StringType(),
387 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
388 NULL);
[email protected]bcb6ee23d2013-02-03 04:06:40389}
390
391void TracingMessageHandler::SaveTraceFileComplete() {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
393 web_ui()->CallJavascriptFunction("tracingController.onSaveTraceFileComplete");
394}
395
[email protected]0cd50aa2013-02-12 22:28:01396void TracingMessageHandler::OnBeginTracing(const base::ListValue* args) {
[email protected]bcb6ee23d2013-02-03 04:06:40397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]dcc78372013-02-23 02:09:53398 DCHECK_GE(args->GetSize(), (size_t) 2);
399 DCHECK_LE(args->GetSize(), (size_t) 3);
[email protected]bcb6ee23d2013-02-03 04:06:40400
401 bool system_tracing_requested = false;
402 bool ok = args->GetBoolean(0, &system_tracing_requested);
403 DCHECK(ok);
404
405 std::string chrome_categories;
406 ok = args->GetString(1, &chrome_categories);
407 DCHECK(ok);
408
[email protected]dcc78372013-02-23 02:09:53409 base::debug::TraceLog::Options options =
410 base::debug::TraceLog::RECORD_UNTIL_FULL;
411 if (args->GetSize() >= 3) {
412 std::string options_;
413 ok = args->GetString(2, &options_);
414 DCHECK(ok);
415 options = base::debug::TraceLog::TraceOptionsFromString(options_);
416 }
417
[email protected]bcb6ee23d2013-02-03 04:06:40418 trace_enabled_ = true;
419 // TODO(jbates) This may fail, but that's OK for current use cases.
420 // Ex: Multiple about:gpu traces can not trace simultaneously.
421 // TODO(nduca) send feedback to javascript about whether or not BeginTracing
422 // was successful.
[email protected]dcc78372013-02-23 02:09:53423 TraceController::GetInstance()->BeginTracing(this, chrome_categories,
424 options);
[email protected]bcb6ee23d2013-02-03 04:06:40425
426 if (system_tracing_requested) {
427#if defined(OS_CHROMEOS)
428 DCHECK(!system_trace_in_progress_);
429 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
430 StartSystemTracing();
431 // TODO(sleffler) async, could wait for completion
432 system_trace_in_progress_ = true;
433#endif
434 }
435}
436
[email protected]0cd50aa2013-02-12 22:28:01437void TracingMessageHandler::OnEndTracingAsync(const base::ListValue* list) {
[email protected]bcb6ee23d2013-02-03 04:06:40438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
439
[email protected]73fbaac2013-05-02 00:40:23440 // This is really us beginning to end tracing, rather than tracing being truly
441 // over. When this function yields, we expect to get some number of
442 // OnTraceDataCollected callbacks, which will append data to window.traceData.
443 // To set up for this, set window.traceData to the empty string.
444 web_ui()->GetWebContents()->GetRenderViewHost()->
445 ExecuteJavascriptInWebFrame(string16(),
446 UTF8ToUTF16("window.traceData = '';"));
447
[email protected]bcb6ee23d2013-02-03 04:06:40448 // TODO(nduca): fix javascript code to make sure trace_enabled_ is always true
449 // here. triggered a false condition by just clicking stop
450 // trace a few times when it was going slow, and maybe switching
451 // between tabs.
452 if (trace_enabled_ &&
453 !TraceController::GetInstance()->EndTracingAsync(this)) {
454 // Set to false now, since it turns out we never were the trace subscriber.
455 OnEndTracingComplete();
456 }
457}
458
459void TracingMessageHandler::OnEndTracingComplete() {
460 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
461 trace_enabled_ = false;
462 if (system_trace_in_progress_) {
463 // Disable system tracing now that the local trace has shutdown.
464 // This must be done last because we potentially need to push event
465 // records into the system event log for synchronizing system event
466 // timestamps with chrome event timestamps--and since the system event
467 // log is a ring-buffer (on linux) adding them at the end is the only
468 // way we're confident we'll have them in the final result.
469 system_trace_in_progress_ = false;
470#if defined(OS_CHROMEOS)
471 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
472 RequestStopSystemTracing(
473 base::Bind(&TracingMessageHandler::OnEndSystemTracingAck,
474 base::Unretained(this)));
475 return;
476#endif
477 }
[email protected]73fbaac2013-05-02 00:40:23478
479 RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
480 rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(
481 "tracingController.onEndTracingComplete(window.traceData);"
482 "delete window.traceData;"));
[email protected]bcb6ee23d2013-02-03 04:06:40483}
484
485void TracingMessageHandler::OnEndSystemTracingAck(
486 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
487 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
488
489 web_ui()->CallJavascriptFunction(
490 "tracingController.onSystemTraceDataCollected",
[email protected]0cd50aa2013-02-12 22:28:01491 *scoped_ptr<base::Value>(new base::StringValue(events_str_ptr->data())));
[email protected]bcb6ee23d2013-02-03 04:06:40492 DCHECK(!system_trace_in_progress_);
493
494 OnEndTracingComplete();
495}
496
497void TracingMessageHandler::OnTraceDataCollected(
498 const scoped_refptr<base::RefCountedString>& trace_fragment) {
499 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
500
[email protected]9e5952e2013-05-18 09:29:01501 std::string javascript;
502 javascript.reserve(trace_fragment->size() * 2);
503 javascript.append("window.traceData += \"");
504 base::JsonDoubleQuote(trace_fragment->data(), false, &javascript);
[email protected]335ec812013-05-03 04:42:16505
[email protected]73fbaac2013-05-02 00:40:23506 // Intentionally append a , to the traceData. This technically causes all
507 // traceData that we pass back to JS to end with a comma, but that is actually
508 // something the JS side strips away anyway
[email protected]9e5952e2013-05-18 09:29:01509 javascript.append(",\";");
[email protected]bcb6ee23d2013-02-03 04:06:40510
511 web_ui()->GetWebContents()->GetRenderViewHost()->
[email protected]73fbaac2013-05-02 00:40:23512 ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(javascript));
[email protected]bcb6ee23d2013-02-03 04:06:40513}
514
515void TracingMessageHandler::OnTraceBufferPercentFullReply(float percent_full) {
516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
517 web_ui()->CallJavascriptFunction(
518 "tracingController.onRequestBufferPercentFullComplete",
[email protected]0cd50aa2013-02-12 22:28:01519 *scoped_ptr<base::Value>(new base::FundamentalValue(percent_full)));
[email protected]bcb6ee23d2013-02-03 04:06:40520}
521
[email protected]3dfd28c92013-03-24 05:36:56522void TracingMessageHandler::OnGetKnownCategories(const base::ListValue* list) {
523 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d936677a2013-04-19 08:49:03524 if (!TraceController::GetInstance()->GetKnownCategoryGroupsAsync(this)) {
[email protected]3dfd28c92013-03-24 05:36:56525 std::set<std::string> ret;
526 OnKnownCategoriesCollected(ret);
527 }
528}
529
530void TracingMessageHandler::OnKnownCategoriesCollected(
531 const std::set<std::string>& known_categories) {
532 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
533
534 scoped_ptr<base::ListValue> categories(new base::ListValue());
[email protected]ad639852013-05-28 03:15:53535 for (std::set<std::string>::const_iterator iter = known_categories.begin();
[email protected]3dfd28c92013-03-24 05:36:56536 iter != known_categories.end();
537 ++iter) {
538 categories->AppendString(*iter);
539 }
540
541 web_ui()->CallJavascriptFunction(
542 "tracingController.onKnownCategoriesCollected", *categories);
543}
544
[email protected]bcb6ee23d2013-02-03 04:06:40545} // namespace
546
547
548////////////////////////////////////////////////////////////////////////////////
549//
550// TracingUI
551//
552////////////////////////////////////////////////////////////////////////////////
553
554TracingUI::TracingUI(WebUI* web_ui) : WebUIController(web_ui) {
555 web_ui->AddMessageHandler(new TracingMessageHandler());
556
557 // Set up the chrome://tracing/ source.
558 BrowserContext* browser_context =
559 web_ui->GetWebContents()->GetBrowserContext();
560 WebUIDataSource::Add(browser_context, CreateTracingHTMLSource());
561}
562
563} // namespace content