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 |