| OLD | NEW |
| (Empty) |
| 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/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" | |
| 14 #include "base/memory/scoped_ptr.h" | |
| 15 #include "base/string_number_conversions.h" | |
| 16 #include "base/stringprintf.h" | |
| 17 #include "base/utf_string_conversions.h" | |
| 18 #include "base/values.h" | |
| 19 #include "content/public/browser/browser_thread.h" | |
| 20 #include "content/public/browser/content_browser_client.h" | |
| 21 #include "content/public/browser/render_view_host.h" | |
| 22 #include "content/public/browser/trace_controller.h" | |
| 23 #include "content/public/browser/trace_subscriber.h" | |
| 24 #include "content/public/browser/web_contents.h" | |
| 25 #include "content/public/browser/web_contents_view.h" | |
| 26 #include "content/public/browser/web_ui.h" | |
| 27 #include "content/public/browser/web_ui_data_source.h" | |
| 28 #include "content/public/browser/web_ui_message_handler.h" | |
| 29 #include "content/public/common/url_constants.h" | |
| 30 #include "grit/content_resources.h" | |
| 31 #include "ipc/ipc_channel.h" | |
| 32 #include "ui/shell_dialogs/select_file_dialog.h" | |
| 33 | |
| 34 #if defined(OS_CHROMEOS) | |
| 35 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 36 #include "chromeos/dbus/debug_daemon_client.h" | |
| 37 #endif | |
| 38 | |
| 39 namespace content { | |
| 40 namespace { | |
| 41 | |
| 42 WebUIDataSource* CreateTracingHTMLSource() { | |
| 43 WebUIDataSource* source = | |
| 44 WebUIDataSource::Create(chrome::kChromeUITracingHost); | |
| 45 | |
| 46 source->SetJsonPath("strings.js"); | |
| 47 source->SetDefaultResource(IDR_TRACING_HTML); | |
| 48 source->AddResourcePath("tracing.js", IDR_TRACING_JS); | |
| 49 source->AddLocalizedString("tracingTitle", IDS_TRACING_TITLE); | |
| 50 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. | |
| 56 class 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. | |
| 66 virtual void RegisterMessages(); | |
| 67 | |
| 68 // SelectFileDialog::Listener implementation | |
| 69 virtual void FileSelected(const FilePath& path, int index, void* params); | |
| 70 virtual void FileSelectionCanceled(void* params); | |
| 71 | |
| 72 // TraceSubscriber implementation. | |
| 73 virtual void OnEndTracingComplete(); | |
| 74 virtual void OnTraceDataCollected( | |
| 75 const scoped_refptr<base::RefCountedString>& trace_fragment); | |
| 76 virtual void OnTraceBufferPercentFullReply(float percent_full); | |
| 77 | |
| 78 // Messages. | |
| 79 void OnTracingControllerInitialized(const ListValue* list); | |
| 80 void OnBeginTracing(const ListValue* list); | |
| 81 void OnEndTracingAsync(const ListValue* list); | |
| 82 void OnBeginRequestBufferPercentFull(const ListValue* list); | |
| 83 void OnLoadTraceFile(const ListValue* list); | |
| 84 void OnSaveTraceFile(const ListValue* list); | |
| 85 | |
| 86 // Callbacks. | |
| 87 void LoadTraceFileComplete(string16* file_contents); | |
| 88 void SaveTraceFileComplete(); | |
| 89 | |
| 90 private: | |
| 91 // The file dialog to select a file for loading or saving traces. | |
| 92 scoped_refptr<ui::SelectFileDialog> select_trace_file_dialog_; | |
| 93 | |
| 94 // The type of the file dialog as the same one is used for loading or saving | |
| 95 // traces. | |
| 96 ui::SelectFileDialog::Type select_trace_file_dialog_type_; | |
| 97 | |
| 98 // The trace data that is to be written to the file on saving. | |
| 99 scoped_ptr<std::string> trace_data_to_save_; | |
| 100 | |
| 101 // True while tracing is active. | |
| 102 bool trace_enabled_; | |
| 103 | |
| 104 // True while system tracing is active. | |
| 105 bool system_trace_in_progress_; | |
| 106 | |
| 107 void OnEndSystemTracingAck( | |
| 108 const scoped_refptr<base::RefCountedString>& events_str_ptr); | |
| 109 | |
| 110 DISALLOW_COPY_AND_ASSIGN(TracingMessageHandler); | |
| 111 }; | |
| 112 | |
| 113 // A proxy passed to the Read and Write tasks used when loading or saving trace | |
| 114 // data. | |
| 115 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> { | |
| 116 public: | |
| 117 explicit TaskProxy(const base::WeakPtr<TracingMessageHandler>& handler) | |
| 118 : handler_(handler) {} | |
| 119 void LoadTraceFileCompleteProxy(string16* file_contents) { | |
| 120 if (handler_) | |
| 121 handler_->LoadTraceFileComplete(file_contents); | |
| 122 delete file_contents; | |
| 123 } | |
| 124 | |
| 125 void SaveTraceFileCompleteProxy() { | |
| 126 if (handler_) | |
| 127 handler_->SaveTraceFileComplete(); | |
| 128 } | |
| 129 | |
| 130 private: | |
| 131 friend class base::RefCountedThreadSafe<TaskProxy>; | |
| 132 ~TaskProxy() {} | |
| 133 | |
| 134 // The message handler to call callbacks on. | |
| 135 base::WeakPtr<TracingMessageHandler> handler_; | |
| 136 | |
| 137 DISALLOW_COPY_AND_ASSIGN(TaskProxy); | |
| 138 }; | |
| 139 | |
| 140 //////////////////////////////////////////////////////////////////////////////// | |
| 141 // | |
| 142 // TracingMessageHandler | |
| 143 // | |
| 144 //////////////////////////////////////////////////////////////////////////////// | |
| 145 | |
| 146 TracingMessageHandler::TracingMessageHandler() | |
| 147 : select_trace_file_dialog_type_(ui::SelectFileDialog::SELECT_NONE), | |
| 148 trace_enabled_(false), | |
| 149 system_trace_in_progress_(false) { | |
| 150 } | |
| 151 | |
| 152 TracingMessageHandler::~TracingMessageHandler() { | |
| 153 if (select_trace_file_dialog_) | |
| 154 select_trace_file_dialog_->ListenerDestroyed(); | |
| 155 | |
| 156 // If we are the current subscriber, this will result in ending tracing. | |
| 157 TraceController::GetInstance()->CancelSubscriber(this); | |
| 158 | |
| 159 // Shutdown any system tracing too. | |
| 160 if (system_trace_in_progress_) { | |
| 161 #if defined(OS_CHROMEOS) | |
| 162 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> | |
| 163 RequestStopSystemTracing( | |
| 164 chromeos::DebugDaemonClient::EmptyStopSystemTracingCallback()); | |
| 165 #endif | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 void TracingMessageHandler::RegisterMessages() { | |
| 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 171 | |
| 172 web_ui()->RegisterMessageCallback("tracingControllerInitialized", | |
| 173 base::Bind(&TracingMessageHandler::OnTracingControllerInitialized, | |
| 174 base::Unretained(this))); | |
| 175 web_ui()->RegisterMessageCallback("beginTracing", | |
| 176 base::Bind(&TracingMessageHandler::OnBeginTracing, | |
| 177 base::Unretained(this))); | |
| 178 web_ui()->RegisterMessageCallback("endTracingAsync", | |
| 179 base::Bind(&TracingMessageHandler::OnEndTracingAsync, | |
| 180 base::Unretained(this))); | |
| 181 web_ui()->RegisterMessageCallback("beginRequestBufferPercentFull", | |
| 182 base::Bind(&TracingMessageHandler::OnBeginRequestBufferPercentFull, | |
| 183 base::Unretained(this))); | |
| 184 web_ui()->RegisterMessageCallback("loadTraceFile", | |
| 185 base::Bind(&TracingMessageHandler::OnLoadTraceFile, | |
| 186 base::Unretained(this))); | |
| 187 web_ui()->RegisterMessageCallback("saveTraceFile", | |
| 188 base::Bind(&TracingMessageHandler::OnSaveTraceFile, | |
| 189 base::Unretained(this))); | |
| 190 } | |
| 191 | |
| 192 void TracingMessageHandler::OnTracingControllerInitialized( | |
| 193 const ListValue* args) { | |
| 194 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 195 | |
| 196 // Send the client info to the tracingController | |
| 197 { | |
| 198 scoped_ptr<DictionaryValue> dict(new DictionaryValue()); | |
| 199 dict->SetString("version", GetContentClient()->GetProduct()); | |
| 200 | |
| 201 dict->SetString("command_line", | |
| 202 CommandLine::ForCurrentProcess()->GetCommandLineString()); | |
| 203 | |
| 204 web_ui()->CallJavascriptFunction("tracingController.onClientInfoUpdate", | |
| 205 *dict); | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 void TracingMessageHandler::OnBeginRequestBufferPercentFull( | |
| 210 const ListValue* list) { | |
| 211 TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this); | |
| 212 } | |
| 213 | |
| 214 // A callback used for asynchronously reading a file to a string. Calls the | |
| 215 // TaskProxy callback when reading is complete. | |
| 216 void ReadTraceFileCallback(TaskProxy* proxy, const FilePath& path) { | |
| 217 std::string file_contents; | |
| 218 if (!file_util::ReadFileToString(path, &file_contents)) | |
| 219 return; | |
| 220 | |
| 221 // We need to escape the file contents, because it will go into a javascript | |
| 222 // quoted string in TracingMessageHandler::LoadTraceFileComplete. We need to | |
| 223 // escape control characters (to have well-formed javascript statements), as | |
| 224 // well as \ and ' (the only special characters in a ''-quoted string). | |
| 225 // Do the escaping on this thread, it may take a little while for big files | |
| 226 // and we don't want to block the UI during that time. Also do the UTF-16 | |
| 227 // conversion here. | |
| 228 // Note: we're using UTF-16 because we'll need to cut the string into slices | |
| 229 // to give to Javascript, and it's easier to cut than UTF-8 (since JS strings | |
| 230 // are arrays of 16-bit values, UCS-2 really, whereas we can't cut inside of a | |
| 231 // multibyte UTF-8 codepoint). | |
| 232 size_t size = file_contents.size(); | |
| 233 std::string escaped_contents; | |
| 234 escaped_contents.reserve(size); | |
| 235 for (size_t i = 0; i < size; ++i) { | |
| 236 char c = file_contents[i]; | |
| 237 if (c < ' ') { | |
| 238 escaped_contents += base::StringPrintf("\\u%04x", c); | |
| 239 continue; | |
| 240 } | |
| 241 if (c == '\\' || c == '\'') | |
| 242 escaped_contents.push_back('\\'); | |
| 243 escaped_contents.push_back(c); | |
| 244 } | |
| 245 file_contents.clear(); | |
| 246 | |
| 247 scoped_ptr<string16> contents16(new string16); | |
| 248 UTF8ToUTF16(escaped_contents).swap(*contents16); | |
| 249 | |
| 250 BrowserThread::PostTask( | |
| 251 BrowserThread::UI, FROM_HERE, | |
| 252 base::Bind(&TaskProxy::LoadTraceFileCompleteProxy, proxy, | |
| 253 contents16.release())); | |
| 254 } | |
| 255 | |
| 256 // A callback used for asynchronously writing a file from a string. Calls the | |
| 257 // TaskProxy callback when writing is complete. | |
| 258 void WriteTraceFileCallback(TaskProxy* proxy, | |
| 259 const FilePath& path, | |
| 260 std::string* contents) { | |
| 261 if (!file_util::WriteFile(path, contents->c_str(), contents->size())) | |
| 262 return; | |
| 263 | |
| 264 BrowserThread::PostTask( | |
| 265 BrowserThread::UI, FROM_HERE, | |
| 266 base::Bind(&TaskProxy::SaveTraceFileCompleteProxy, proxy)); | |
| 267 } | |
| 268 | |
| 269 void TracingMessageHandler::FileSelected( | |
| 270 const FilePath& path, int index, void* params) { | |
| 271 if (select_trace_file_dialog_type_ == | |
| 272 ui::SelectFileDialog::SELECT_OPEN_FILE) { | |
| 273 BrowserThread::PostTask( | |
| 274 BrowserThread::FILE, FROM_HERE, | |
| 275 base::Bind(&ReadTraceFileCallback, | |
| 276 make_scoped_refptr(new TaskProxy(AsWeakPtr())), path)); | |
| 277 } else { | |
| 278 BrowserThread::PostTask( | |
| 279 BrowserThread::FILE, FROM_HERE, | |
| 280 base::Bind(&WriteTraceFileCallback, | |
| 281 make_scoped_refptr(new TaskProxy(AsWeakPtr())), path, | |
| 282 trace_data_to_save_.release())); | |
| 283 } | |
| 284 | |
| 285 select_trace_file_dialog_ = NULL; | |
| 286 } | |
| 287 | |
| 288 void TracingMessageHandler::FileSelectionCanceled(void* params) { | |
| 289 select_trace_file_dialog_ = NULL; | |
| 290 if (select_trace_file_dialog_type_ == | |
| 291 ui::SelectFileDialog::SELECT_OPEN_FILE) { | |
| 292 web_ui()->CallJavascriptFunction( | |
| 293 "tracingController.onLoadTraceFileCanceled"); | |
| 294 } else { | |
| 295 web_ui()->CallJavascriptFunction( | |
| 296 "tracingController.onSaveTraceFileCanceled"); | |
| 297 } | |
| 298 } | |
| 299 | |
| 300 void TracingMessageHandler::OnLoadTraceFile(const ListValue* list) { | |
| 301 // Only allow a single dialog at a time. | |
| 302 if (select_trace_file_dialog_.get()) | |
| 303 return; | |
| 304 select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE; | |
| 305 select_trace_file_dialog_ = ui::SelectFileDialog::Create( | |
| 306 this, | |
| 307 GetContentClient()->browser()->CreateSelectFilePolicy( | |
| 308 web_ui()->GetWebContents())); | |
| 309 select_trace_file_dialog_->SelectFile( | |
| 310 ui::SelectFileDialog::SELECT_OPEN_FILE, | |
| 311 string16(), | |
| 312 FilePath(), | |
| 313 NULL, 0, FILE_PATH_LITERAL(""), | |
| 314 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(), NULL); | |
| 315 } | |
| 316 | |
| 317 void TracingMessageHandler::LoadTraceFileComplete(string16* contents) { | |
| 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 319 | |
| 320 // We need to pass contents to tracingController.onLoadTraceFileComplete, but | |
| 321 // that may be arbitrarily big, and IPCs messages are limited in size. So we | |
| 322 // need to cut it into pieces and rebuild the string in Javascript. | |
| 323 // |contents| has already been escaped in ReadTraceFileCallback. | |
| 324 // IPC::Channel::kMaximumMessageSize is in bytes, and we need to account for | |
| 325 // overhead. | |
| 326 const size_t kMaxSize = IPC::Channel::kMaximumMessageSize / 2 - 128; | |
| 327 string16 first_prefix = UTF8ToUTF16("window.traceData = '"); | |
| 328 string16 prefix = UTF8ToUTF16("window.traceData += '"); | |
| 329 string16 suffix = UTF8ToUTF16("';"); | |
| 330 | |
| 331 RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost(); | |
| 332 for (size_t i = 0; i < contents->size(); i += kMaxSize) { | |
| 333 string16 javascript = i == 0 ? first_prefix : prefix; | |
| 334 javascript += contents->substr(i, kMaxSize) + suffix; | |
| 335 rvh->ExecuteJavascriptInWebFrame(string16(), javascript); | |
| 336 } | |
| 337 rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16( | |
| 338 "tracingController.onLoadTraceFileComplete(JSON.parse(window.traceData));" | |
| 339 "delete window.traceData;")); | |
| 340 } | |
| 341 | |
| 342 void TracingMessageHandler::OnSaveTraceFile(const ListValue* list) { | |
| 343 // Only allow a single dialog at a time. | |
| 344 if (select_trace_file_dialog_.get()) | |
| 345 return; | |
| 346 | |
| 347 DCHECK(list->GetSize() == 1); | |
| 348 | |
| 349 std::string* trace_data = new std::string(); | |
| 350 bool ok = list->GetString(0, trace_data); | |
| 351 DCHECK(ok); | |
| 352 trace_data_to_save_.reset(trace_data); | |
| 353 | |
| 354 select_trace_file_dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE; | |
| 355 select_trace_file_dialog_ = ui::SelectFileDialog::Create( | |
| 356 this, | |
| 357 GetContentClient()->browser()->CreateSelectFilePolicy( | |
| 358 web_ui()->GetWebContents())); | |
| 359 select_trace_file_dialog_->SelectFile( | |
| 360 ui::SelectFileDialog::SELECT_SAVEAS_FILE, | |
| 361 string16(), | |
| 362 FilePath(), | |
| 363 NULL, 0, FILE_PATH_LITERAL(""), | |
| 364 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(), NULL); | |
| 365 } | |
| 366 | |
| 367 void TracingMessageHandler::SaveTraceFileComplete() { | |
| 368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 369 web_ui()->CallJavascriptFunction("tracingController.onSaveTraceFileComplete"); | |
| 370 } | |
| 371 | |
| 372 void TracingMessageHandler::OnBeginTracing(const ListValue* args) { | |
| 373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 374 DCHECK_EQ(args->GetSize(), (size_t) 2); | |
| 375 | |
| 376 bool system_tracing_requested = false; | |
| 377 bool ok = args->GetBoolean(0, &system_tracing_requested); | |
| 378 DCHECK(ok); | |
| 379 | |
| 380 std::string chrome_categories; | |
| 381 ok = args->GetString(1, &chrome_categories); | |
| 382 DCHECK(ok); | |
| 383 | |
| 384 trace_enabled_ = true; | |
| 385 // TODO(jbates) This may fail, but that's OK for current use cases. | |
| 386 // Ex: Multiple about:gpu traces can not trace simultaneously. | |
| 387 // TODO(nduca) send feedback to javascript about whether or not BeginTracing | |
| 388 // was successful. | |
| 389 TraceController::GetInstance()->BeginTracing(this, chrome_categories); | |
| 390 | |
| 391 if (system_tracing_requested) { | |
| 392 #if defined(OS_CHROMEOS) | |
| 393 DCHECK(!system_trace_in_progress_); | |
| 394 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> | |
| 395 StartSystemTracing(); | |
| 396 // TODO(sleffler) async, could wait for completion | |
| 397 system_trace_in_progress_ = true; | |
| 398 #endif | |
| 399 } | |
| 400 } | |
| 401 | |
| 402 void TracingMessageHandler::OnEndTracingAsync(const ListValue* list) { | |
| 403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 404 | |
| 405 // TODO(nduca): fix javascript code to make sure trace_enabled_ is always true | |
| 406 // here. triggered a false condition by just clicking stop | |
| 407 // trace a few times when it was going slow, and maybe switching | |
| 408 // between tabs. | |
| 409 if (trace_enabled_ && | |
| 410 !TraceController::GetInstance()->EndTracingAsync(this)) { | |
| 411 // Set to false now, since it turns out we never were the trace subscriber. | |
| 412 OnEndTracingComplete(); | |
| 413 } | |
| 414 } | |
| 415 | |
| 416 void TracingMessageHandler::OnEndTracingComplete() { | |
| 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 418 trace_enabled_ = false; | |
| 419 if (system_trace_in_progress_) { | |
| 420 // Disable system tracing now that the local trace has shutdown. | |
| 421 // This must be done last because we potentially need to push event | |
| 422 // records into the system event log for synchronizing system event | |
| 423 // timestamps with chrome event timestamps--and since the system event | |
| 424 // log is a ring-buffer (on linux) adding them at the end is the only | |
| 425 // way we're confident we'll have them in the final result. | |
| 426 system_trace_in_progress_ = false; | |
| 427 #if defined(OS_CHROMEOS) | |
| 428 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> | |
| 429 RequestStopSystemTracing( | |
| 430 base::Bind(&TracingMessageHandler::OnEndSystemTracingAck, | |
| 431 base::Unretained(this))); | |
| 432 return; | |
| 433 #endif | |
| 434 } | |
| 435 web_ui()->CallJavascriptFunction("tracingController.onEndTracingComplete"); | |
| 436 } | |
| 437 | |
| 438 void TracingMessageHandler::OnEndSystemTracingAck( | |
| 439 const scoped_refptr<base::RefCountedString>& events_str_ptr) { | |
| 440 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 441 | |
| 442 web_ui()->CallJavascriptFunction( | |
| 443 "tracingController.onSystemTraceDataCollected", | |
| 444 *scoped_ptr<Value>(Value::CreateStringValue(events_str_ptr->data()))); | |
| 445 DCHECK(!system_trace_in_progress_); | |
| 446 | |
| 447 OnEndTracingComplete(); | |
| 448 } | |
| 449 | |
| 450 void TracingMessageHandler::OnTraceDataCollected( | |
| 451 const scoped_refptr<base::RefCountedString>& trace_fragment) { | |
| 452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 453 | |
| 454 base::debug::TraceResultBuffer::SimpleOutput output; | |
| 455 base::debug::TraceResultBuffer trace_buffer; | |
| 456 trace_buffer.SetOutputCallback(output.GetCallback()); | |
| 457 output.Append("tracingController.onTraceDataCollected("); | |
| 458 trace_buffer.Start(); | |
| 459 trace_buffer.AddFragment(trace_fragment->data()); | |
| 460 trace_buffer.Finish(); | |
| 461 output.Append(");"); | |
| 462 | |
| 463 web_ui()->GetWebContents()->GetRenderViewHost()-> | |
| 464 ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(output.json_output)); | |
| 465 } | |
| 466 | |
| 467 void TracingMessageHandler::OnTraceBufferPercentFullReply(float percent_full) { | |
| 468 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 469 web_ui()->CallJavascriptFunction( | |
| 470 "tracingController.onRequestBufferPercentFullComplete", | |
| 471 *scoped_ptr<Value>(Value::CreateDoubleValue(percent_full))); | |
| 472 } | |
| 473 | |
| 474 } // namespace | |
| 475 | |
| 476 | |
| 477 //////////////////////////////////////////////////////////////////////////////// | |
| 478 // | |
| 479 // TracingUI | |
| 480 // | |
| 481 //////////////////////////////////////////////////////////////////////////////// | |
| 482 | |
| 483 TracingUI::TracingUI(WebUI* web_ui) : WebUIController(web_ui) { | |
| 484 web_ui->AddMessageHandler(new TracingMessageHandler()); | |
| 485 | |
| 486 // Set up the chrome://tracing/ source. | |
| 487 BrowserContext* browser_context = | |
| 488 web_ui->GetWebContents()->GetBrowserContext(); | |
| 489 WebUIDataSource::Add(browser_context, CreateTracingHTMLSource()); | |
| 490 } | |
| 491 | |
| 492 } // namespace content | |
| OLD | NEW |