Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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/command_line.h" | |
| 10 #include "base/file_util.h" | |
| 11 #include "base/scoped_ptr.h" | |
| 12 #include "base/string_number_conversions.h" | |
| 13 #include "base/utf_string_conversions.h" | |
| 14 #include "chrome/browser/profiles/profile.h" | |
| 15 #include "chrome/browser/ui/shell_dialogs.h" | |
| 16 #include "chrome/browser/ui/webui/chrome_web_ui_data_source.h" | |
| 17 #include "chrome/common/chrome_version_info.h" | |
| 18 #include "chrome/common/url_constants.h" | |
| 19 #include "content/browser/gpu/gpu_data_manager.h" | |
| 20 #include "content/browser/renderer_host/render_view_host.h" | |
| 21 #include "content/browser/tab_contents/tab_contents.h" | |
| 22 #include "content/browser/tab_contents/tab_contents_view.h" | |
| 23 #include "content/browser/trace_controller.h" | |
| 24 #include "grit/browser_resources.h" | |
| 25 #include "grit/generated_resources.h" | |
| 26 #include "ui/base/l10n/l10n_util.h" | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 ChromeWebUIDataSource* CreateTracingHTMLSource() { | |
| 31 ChromeWebUIDataSource* source = | |
| 32 new ChromeWebUIDataSource(chrome::kChromeUITracingHost); | |
| 33 | |
| 34 source->set_json_path("strings.js"); | |
| 35 source->add_resource_path("tracing.js", IDR_TRACING_JS); | |
| 36 source->set_default_resource(IDR_TRACING_HTML); | |
| 37 return source; | |
| 38 } | |
| 39 | |
| 40 // This class receives javascript messages from the renderer. | |
| 41 // Note that the WebUI infrastructure runs on the UI thread, therefore all of | |
| 42 // this class's methods are expected to run on the UI thread. | |
| 43 class TracingMessageHandler | |
| 44 : public WebUIMessageHandler, | |
| 45 public SelectFileDialog::Listener, | |
| 46 public base::SupportsWeakPtr<TracingMessageHandler>, | |
| 47 public TraceSubscriber { | |
| 48 public: | |
| 49 TracingMessageHandler(); | |
| 50 virtual ~TracingMessageHandler(); | |
| 51 | |
| 52 // WebUIMessageHandler implementation. | |
| 53 virtual WebUIMessageHandler* Attach(WebUI* web_ui); | |
| 54 virtual void RegisterMessages(); | |
| 55 | |
| 56 // Mesages | |
|
James Hawkins
2011/08/04 17:26:35
You're intermingling added methods with interface
dominich
2011/08/04 22:56:12
Done.
| |
| 57 void OnBeginTracing(const ListValue* list); | |
| 58 void OnEndTracingAsync(const ListValue* list); | |
| 59 void OnBeginRequestBufferPercentFull(const ListValue* list); | |
| 60 void OnLoadTraceFile(const ListValue* list); | |
| 61 void OnSaveTraceFile(const ListValue* list); | |
| 62 | |
| 63 // SelectFileDialog::Listener implementation | |
| 64 virtual void FileSelected(const FilePath& path, int index, void* params); | |
| 65 virtual void FileSelectionCanceled(void* params); | |
| 66 | |
| 67 // Callbacks. | |
| 68 void LoadTraceFileComplete(std::string* file_contents); | |
| 69 void SaveTraceFileComplete(); | |
| 70 | |
| 71 // TraceSubscriber implementation. | |
| 72 virtual void OnEndTracingComplete(); | |
| 73 virtual void OnTraceDataCollected(const std::string& json_events); | |
| 74 virtual void OnTraceBufferPercentFullReply(float percent_full); | |
| 75 | |
| 76 // Executes the javascript function |function_name| in the renderer, passing | |
| 77 // it the argument |value|. | |
| 78 void CallJavascriptFunction(const std::wstring& function_name, | |
| 79 const Value* value); | |
| 80 | |
| 81 private: | |
| 82 DISALLOW_COPY_AND_ASSIGN(TracingMessageHandler); | |
|
James Hawkins
2011/08/04 17:26:35
This should be at the bottom of the class.
dominich
2011/08/04 22:56:12
Done.
| |
| 83 | |
| 84 scoped_refptr<SelectFileDialog> select_trace_file_dialog_; | |
|
James Hawkins
2011/08/04 17:26:35
Document vars.
dominich
2011/08/04 22:56:12
Done.
| |
| 85 SelectFileDialog::Type select_trace_file_dialog_type_; | |
| 86 scoped_ptr<std::string> trace_data_to_save_; | |
| 87 | |
| 88 bool trace_enabled_; | |
| 89 }; | |
| 90 | |
| 91 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> { | |
|
James Hawkins
2011/08/04 17:26:35
Document this class.
dominich
2011/08/04 22:56:12
Done.
| |
| 92 public: | |
| 93 explicit TaskProxy(const base::WeakPtr<TracingMessageHandler>& handler) | |
| 94 : handler_(handler) {} | |
| 95 void LoadTraceFileCompleteProxy(std::string* file_contents) { | |
| 96 if (handler_) | |
| 97 handler_->LoadTraceFileComplete(file_contents); | |
| 98 delete file_contents; | |
| 99 } | |
| 100 | |
| 101 void SaveTraceFileCompleteProxy() { | |
| 102 if (handler_) | |
| 103 handler_->SaveTraceFileComplete(); | |
| 104 } | |
| 105 | |
| 106 private: | |
| 107 base::WeakPtr<TracingMessageHandler> handler_; | |
|
James Hawkins
2011/08/04 17:26:35
Document vars.
dominich
2011/08/04 22:56:12
Done.
| |
| 108 friend class base::RefCountedThreadSafe<TaskProxy>; | |
| 109 DISALLOW_COPY_AND_ASSIGN(TaskProxy); | |
| 110 }; | |
| 111 | |
| 112 //////////////////////////////////////////////////////////////////////////////// | |
| 113 // | |
| 114 // TracingMessageHandler | |
| 115 // | |
| 116 //////////////////////////////////////////////////////////////////////////////// | |
| 117 | |
| 118 TracingMessageHandler::TracingMessageHandler() | |
| 119 : select_trace_file_dialog_type_(SelectFileDialog::SELECT_NONE), | |
| 120 trace_enabled_(false) { | |
| 121 } | |
| 122 | |
| 123 TracingMessageHandler::~TracingMessageHandler() { | |
| 124 if (select_trace_file_dialog_) | |
| 125 select_trace_file_dialog_->ListenerDestroyed(); | |
| 126 | |
| 127 // If we are the current subscriber, this will result in ending tracing. | |
| 128 TraceController::GetInstance()->CancelSubscriber(this); | |
| 129 } | |
| 130 | |
| 131 WebUIMessageHandler* TracingMessageHandler::Attach(WebUI* web_ui) { | |
| 132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 133 WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui); | |
| 134 return result; | |
| 135 } | |
| 136 | |
| 137 void TracingMessageHandler::RegisterMessages() { | |
| 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 139 | |
| 140 web_ui_->RegisterMessageCallback( | |
| 141 "beginTracing", | |
| 142 NewCallback(this, &TracingMessageHandler::OnBeginTracing)); | |
| 143 web_ui_->RegisterMessageCallback( | |
| 144 "endTracingAsync", | |
| 145 NewCallback(this, &TracingMessageHandler::OnEndTracingAsync)); | |
| 146 web_ui_->RegisterMessageCallback( | |
| 147 "beginRequestBufferPercentFull", | |
| 148 NewCallback(this, | |
| 149 &TracingMessageHandler::OnBeginRequestBufferPercentFull)); | |
| 150 web_ui_->RegisterMessageCallback( | |
| 151 "loadTraceFile", | |
| 152 NewCallback(this, &TracingMessageHandler::OnLoadTraceFile)); | |
| 153 web_ui_->RegisterMessageCallback( | |
| 154 "saveTraceFile", | |
| 155 NewCallback(this, &TracingMessageHandler::OnSaveTraceFile)); | |
| 156 } | |
| 157 | |
| 158 void TracingMessageHandler::OnBeginRequestBufferPercentFull( | |
| 159 const ListValue* list) { | |
| 160 TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this); | |
| 161 } | |
| 162 | |
| 163 class ReadTraceFileTask : public Task { | |
| 164 public: | |
| 165 ReadTraceFileTask(TaskProxy* proxy, const FilePath& path) | |
| 166 : proxy_(proxy) | |
| 167 , path_(path) {} | |
|
James Hawkins
2011/08/04 17:26:35
Comma must be on the previous line.
dominich
2011/08/04 22:56:12
Done.
| |
| 168 | |
| 169 virtual void Run() { | |
| 170 std::string* file_contents = new std::string(); | |
| 171 if (!file_util::ReadFileToString(path_, file_contents)) { | |
| 172 delete file_contents; | |
| 173 return; | |
| 174 } | |
| 175 BrowserThread::PostTask( | |
| 176 BrowserThread::UI, FROM_HERE, | |
| 177 NewRunnableMethod(proxy_.get(), | |
| 178 &TaskProxy::LoadTraceFileCompleteProxy, | |
| 179 file_contents)); | |
| 180 } | |
| 181 | |
| 182 private: | |
| 183 scoped_refptr<TaskProxy> proxy_; | |
| 184 | |
| 185 // Path of the file to open. | |
| 186 const FilePath path_; | |
| 187 }; | |
| 188 | |
| 189 class WriteTraceFileTask : public Task { | |
|
James Hawkins
2011/08/04 17:26:35
Document class.
dominich
2011/08/04 22:56:12
Done.
| |
| 190 public: | |
| 191 WriteTraceFileTask(TaskProxy* proxy, | |
| 192 const FilePath& path, | |
| 193 std::string* contents) | |
| 194 : proxy_(proxy) | |
| 195 , path_(path) | |
| 196 , contents_(contents) {} | |
| 197 | |
| 198 virtual void Run() { | |
| 199 if (!file_util::WriteFile(path_, contents_->c_str(), contents_->size())) | |
| 200 return; | |
| 201 BrowserThread::PostTask( | |
| 202 BrowserThread::UI, FROM_HERE, | |
| 203 NewRunnableMethod(proxy_.get(), | |
| 204 &TaskProxy::SaveTraceFileCompleteProxy)); | |
| 205 } | |
| 206 | |
| 207 private: | |
| 208 scoped_refptr<TaskProxy> proxy_; | |
| 209 | |
| 210 // Path of the file to save. | |
| 211 const FilePath path_; | |
| 212 | |
| 213 // What to save | |
| 214 scoped_ptr<std::string> contents_; | |
| 215 }; | |
| 216 | |
| 217 void TracingMessageHandler::FileSelected( | |
| 218 const FilePath& path, int index, void* params) { | |
| 219 if (select_trace_file_dialog_type_ == SelectFileDialog::SELECT_OPEN_FILE) | |
| 220 BrowserThread::PostTask( | |
| 221 BrowserThread::FILE, FROM_HERE, | |
| 222 new ReadTraceFileTask(new TaskProxy(AsWeakPtr()), path)); | |
| 223 else | |
| 224 BrowserThread::PostTask( | |
| 225 BrowserThread::FILE, FROM_HERE, | |
| 226 new WriteTraceFileTask(new TaskProxy(AsWeakPtr()), path, | |
| 227 trace_data_to_save_.release())); | |
| 228 select_trace_file_dialog_.release(); | |
| 229 } | |
| 230 | |
| 231 void TracingMessageHandler::FileSelectionCanceled(void* params) { | |
| 232 select_trace_file_dialog_.release(); | |
| 233 if (select_trace_file_dialog_type_ == SelectFileDialog::SELECT_OPEN_FILE) { | |
| 234 web_ui_->CallJavascriptFunction( | |
| 235 "tracingController.onLoadTraceFileCanceled"); | |
| 236 } else { | |
| 237 web_ui_->CallJavascriptFunction( | |
| 238 "tracingController.onSaveTraceFileCanceled"); | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 void TracingMessageHandler::OnLoadTraceFile(const ListValue* list) { | |
| 243 // Only allow a single dialog at a time. | |
| 244 if (select_trace_file_dialog_.get()) | |
| 245 return; | |
| 246 select_trace_file_dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE; | |
| 247 select_trace_file_dialog_ = SelectFileDialog::Create(this); | |
| 248 select_trace_file_dialog_->SelectFile( | |
| 249 SelectFileDialog::SELECT_OPEN_FILE, | |
| 250 string16(), | |
| 251 FilePath(), | |
| 252 NULL, 0, FILE_PATH_LITERAL(""), web_ui_->tab_contents(), | |
| 253 web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); | |
| 254 } | |
| 255 | |
| 256 void TracingMessageHandler::LoadTraceFileComplete(std::string* file_contents) { | |
| 257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 258 std::wstring javascript; | |
| 259 javascript += L"tracingController.onLoadTraceFileComplete("; | |
| 260 javascript += UTF8ToWide(*file_contents); | |
| 261 javascript += L");"; | |
| 262 | |
| 263 web_ui_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(string16(), | |
| 264 WideToUTF16Hack(javascript)); | |
| 265 } | |
| 266 | |
| 267 void TracingMessageHandler::OnSaveTraceFile(const ListValue* list) { | |
| 268 // Only allow a single dialog at a time. | |
| 269 if (select_trace_file_dialog_.get()) | |
| 270 return; | |
| 271 | |
| 272 DCHECK(list->GetSize() == 1); | |
| 273 | |
| 274 std::string* trace_data = new std::string(); | |
| 275 bool ok = list->GetString(0, trace_data); | |
| 276 DCHECK(ok); | |
| 277 trace_data_to_save_.reset(trace_data); | |
| 278 | |
| 279 select_trace_file_dialog_type_ = SelectFileDialog::SELECT_SAVEAS_FILE; | |
| 280 select_trace_file_dialog_ = SelectFileDialog::Create(this); | |
| 281 select_trace_file_dialog_->SelectFile( | |
| 282 SelectFileDialog::SELECT_SAVEAS_FILE, | |
| 283 string16(), | |
| 284 FilePath(), | |
| 285 NULL, 0, FILE_PATH_LITERAL(""), web_ui_->tab_contents(), | |
| 286 web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); | |
| 287 } | |
| 288 | |
| 289 void TracingMessageHandler::SaveTraceFileComplete() { | |
| 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 291 std::wstring javascript; | |
| 292 web_ui_->CallJavascriptFunction("tracingController.onSaveTraceFileComplete"); | |
| 293 } | |
| 294 | |
| 295 DictionaryValue* NewDescriptionValuePair(const std::string& desc, | |
| 296 const std::string& value) { | |
| 297 DictionaryValue* dict = new DictionaryValue(); | |
| 298 dict->SetString("description", desc); | |
| 299 dict->SetString("value", value); | |
| 300 return dict; | |
| 301 } | |
| 302 | |
| 303 DictionaryValue* NewDescriptionValuePair(const std::string& desc, | |
| 304 Value* value) { | |
| 305 DictionaryValue* dict = new DictionaryValue(); | |
| 306 dict->SetString("description", desc); | |
| 307 dict->Set("value", value); | |
| 308 return dict; | |
| 309 } | |
| 310 | |
| 311 void TracingMessageHandler::OnBeginTracing(const ListValue* args) { | |
| 312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 313 trace_enabled_ = true; | |
| 314 // TODO(jbates) This may fail, but that's OK for current use cases. | |
| 315 // Ex: Multiple about:gpu traces can not trace simultaneously. | |
| 316 // TODO(nduca) send feedback to javascript about whether or not BeginTracing | |
| 317 // was successful. | |
| 318 TraceController::GetInstance()->BeginTracing(this); | |
| 319 } | |
| 320 | |
| 321 void TracingMessageHandler::OnEndTracingAsync(const ListValue* list) { | |
| 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 323 | |
| 324 // TODO(nduca): fix javascript code to make sure trace_enabled_ is always true | |
| 325 // here. triggered a false condition by just clicking stop | |
| 326 // trace a few times when it was going slow, and maybe switching | |
| 327 // between tabs. | |
| 328 if (trace_enabled_ && | |
| 329 !TraceController::GetInstance()->EndTracingAsync(this)) { | |
| 330 // Set to false now, since it turns out we never were the trace subscriber. | |
| 331 OnEndTracingComplete(); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 void TracingMessageHandler::OnEndTracingComplete() { | |
| 336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 337 trace_enabled_ = false; | |
| 338 web_ui_->CallJavascriptFunction("tracingController.onEndTracingComplete"); | |
| 339 } | |
| 340 | |
| 341 void TracingMessageHandler::OnTraceDataCollected( | |
| 342 const std::string& json_events) { | |
| 343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 344 std::wstring javascript; | |
| 345 javascript += L"tracingController.onTraceDataCollected("; | |
| 346 javascript += UTF8ToWide(json_events); | |
| 347 javascript += L");"; | |
| 348 | |
| 349 web_ui_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(string16(), | |
| 350 WideToUTF16Hack(javascript)); | |
| 351 } | |
| 352 | |
| 353 void TracingMessageHandler::OnTraceBufferPercentFullReply(float percent_full) { | |
| 354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 355 web_ui_->CallJavascriptFunction( | |
| 356 "tracingController.onRequestBufferPercentFullComplete", | |
| 357 *scoped_ptr<Value>(Value::CreateDoubleValue(percent_full))); | |
| 358 } | |
| 359 | |
| 360 } // namespace | |
| 361 | |
| 362 | |
| 363 //////////////////////////////////////////////////////////////////////////////// | |
| 364 // | |
| 365 // TracingUI | |
| 366 // | |
| 367 //////////////////////////////////////////////////////////////////////////////// | |
| 368 | |
| 369 TracingUI::TracingUI(TabContents* contents) : ChromeWebUI(contents) { | |
| 370 printf("TracingUI::TracingUI\n"); | |
| 371 AddMessageHandler((new TracingMessageHandler())->Attach(this)); | |
| 372 | |
| 373 // Set up the chrome://tracing/ source. | |
| 374 Profile::FromBrowserContext(contents->browser_context())-> | |
| 375 GetChromeURLDataManager()->AddDataSource(CreateTracingHTMLSource()); | |
| 376 } | |
| OLD | NEW |