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