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/workers_ui.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/json/json_writer.h" | |
10 #include "base/memory/ref_counted_memory.h" | |
11 #include "base/string_number_conversions.h" | |
12 #include "base/string_util.h" | |
13 #include "base/values.h" | |
14 #include "chrome/browser/debugger/devtools_window.h" | |
15 #include "chrome/browser/profiles/profile.h" | |
16 #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h" | |
17 #include "chrome/browser/ui/webui/chrome_web_ui_data_source.h" | |
18 #include "chrome/common/url_constants.h" | |
19 #include "content/public/browser/child_process_data.h" | |
20 #include "content/public/browser/devtools_agent_host_registry.h" | |
21 #include "content/public/browser/browser_thread.h" | |
22 #include "content/public/browser/web_contents.h" | |
23 #include "content/public/browser/web_ui.h" | |
24 #include "content/public/browser/worker_service.h" | |
25 #include "content/public/browser/worker_service_observer.h" | |
26 #include "content/public/browser/web_ui_message_handler.h" | |
27 #include "content/public/common/process_type.h" | |
28 #include "grit/generated_resources.h" | |
29 #include "grit/workers_resources.h" | |
30 #include "ui/base/resource/resource_bundle.h" | |
31 | |
32 using content::BrowserThread; | |
33 using content::ChildProcessData; | |
34 using content::DevToolsAgentHost; | |
35 using content::DevToolsAgentHostRegistry; | |
36 using content::WebContents; | |
37 using content::WebUIMessageHandler; | |
38 using content::WorkerService; | |
39 using content::WorkerServiceObserver; | |
40 | |
41 static const char kWorkersDataFile[] = "workers_data.json"; | |
42 | |
43 static const char kOpenDevToolsCommand[] = "openDevTools"; | |
44 static const char kTerminateWorkerCommand[] = "terminateWorker"; | |
45 | |
46 static const char kWorkerProcessHostIdField[] = "workerProcessHostId"; | |
47 static const char kWorkerRouteIdField[] = "workerRouteId"; | |
48 static const char kUrlField[] = "url"; | |
49 static const char kNameField[] = "name"; | |
50 static const char kPidField[] = "pid"; | |
51 | |
52 namespace { | |
53 | |
54 | |
55 DictionaryValue* BuildWorkerData( | |
56 const GURL& url, | |
57 const string16& name, | |
58 int process_id, | |
59 int route_id, | |
60 base::ProcessHandle handle) { | |
61 DictionaryValue* worker_data = new DictionaryValue(); | |
62 worker_data->SetInteger(kWorkerProcessHostIdField, process_id); | |
63 worker_data->SetInteger(kWorkerRouteIdField, route_id); | |
64 worker_data->SetString(kUrlField, url.spec()); | |
65 worker_data->SetString(kNameField, name); | |
66 worker_data->SetInteger(kPidField, base::GetProcId(handle)); | |
67 return worker_data; | |
68 } | |
69 | |
70 class WorkersUIHTMLSource : public ChromeWebUIDataSource { | |
71 public: | |
72 WorkersUIHTMLSource(); | |
73 | |
74 virtual void StartDataRequest(const std::string& path, | |
75 bool is_incognito, | |
76 int request_id); | |
77 private: | |
78 ~WorkersUIHTMLSource() {} | |
79 void SendSharedWorkersData(int request_id); | |
80 DISALLOW_COPY_AND_ASSIGN(WorkersUIHTMLSource); | |
81 }; | |
82 | |
83 WorkersUIHTMLSource::WorkersUIHTMLSource() | |
84 : ChromeWebUIDataSource(chrome::kChromeUIWorkersHost, NULL) { | |
85 add_resource_path("workers.js", IDR_WORKERS_INDEX_JS); | |
86 set_default_resource(IDR_WORKERS_INDEX_HTML); | |
87 } | |
88 | |
89 void WorkersUIHTMLSource::StartDataRequest(const std::string& path, | |
90 bool is_incognito, | |
91 int request_id) { | |
92 if (path == kWorkersDataFile) { | |
93 SendSharedWorkersData(request_id); | |
94 } else { | |
95 ChromeWebUIDataSource::StartDataRequest(path, is_incognito, request_id); | |
96 } | |
97 } | |
98 | |
99 void WorkersUIHTMLSource::SendSharedWorkersData(int request_id) { | |
100 ListValue workers_list; | |
101 std::vector<WorkerService::WorkerInfo> worker_info = | |
102 WorkerService::GetInstance()->GetWorkers(); | |
103 for (size_t i = 0; i < worker_info.size(); ++i) { | |
104 workers_list.Append(BuildWorkerData( | |
105 worker_info[i].url, worker_info[i].name, worker_info[i].process_id, | |
106 worker_info[i].route_id, worker_info[i].handle)); | |
107 } | |
108 | |
109 std::string json_string; | |
110 base::JSONWriter::Write(&workers_list, &json_string); | |
111 | |
112 SendResponse(request_id, base::RefCountedString::TakeString(&json_string)); | |
113 } | |
114 | |
115 class WorkersDOMHandler : public WebUIMessageHandler { | |
116 public: | |
117 WorkersDOMHandler() {} | |
118 virtual ~WorkersDOMHandler() {} | |
119 | |
120 private: | |
121 // WebUIMessageHandler implementation. | |
122 virtual void RegisterMessages() OVERRIDE; | |
123 | |
124 // Callback for "openDevTools" message. | |
125 void HandleOpenDevTools(const ListValue* args); | |
126 void HandleTerminateWorker(const ListValue* args); | |
127 | |
128 DISALLOW_COPY_AND_ASSIGN(WorkersDOMHandler); | |
129 }; | |
130 | |
131 void WorkersDOMHandler::RegisterMessages() { | |
132 web_ui()->RegisterMessageCallback(kOpenDevToolsCommand, | |
133 base::Bind(&WorkersDOMHandler::HandleOpenDevTools, | |
134 base::Unretained(this))); | |
135 web_ui()->RegisterMessageCallback(kTerminateWorkerCommand, | |
136 base::Bind(&WorkersDOMHandler::HandleTerminateWorker, | |
137 base::Unretained(this))); | |
138 } | |
139 | |
140 void WorkersDOMHandler::HandleOpenDevTools(const ListValue* args) { | |
141 std::string worker_process_host_id_str; | |
142 std::string worker_route_id_str; | |
143 int worker_process_host_id; | |
144 int worker_route_id; | |
145 CHECK(args->GetSize() == 2); | |
146 CHECK(args->GetString(0, &worker_process_host_id_str)); | |
147 CHECK(args->GetString(1, &worker_route_id_str)); | |
148 CHECK(base::StringToInt(worker_process_host_id_str, | |
149 &worker_process_host_id)); | |
150 CHECK(base::StringToInt(worker_route_id_str, &worker_route_id)); | |
151 | |
152 Profile* profile = Profile::FromWebUI(web_ui()); | |
153 if (!profile) | |
154 return; | |
155 DevToolsAgentHost* agent_host = | |
156 DevToolsAgentHostRegistry::GetDevToolsAgentHostForWorker( | |
157 worker_process_host_id, | |
158 worker_route_id); | |
159 DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host); | |
160 } | |
161 | |
162 static void TerminateWorker(int process_id, int route_id) { | |
163 WorkerService::GetInstance()->TerminateWorker(process_id, route_id); | |
164 } | |
165 | |
166 void WorkersDOMHandler::HandleTerminateWorker(const ListValue* args) { | |
167 std::string worker_process_host_id_str; | |
168 std::string worker_route_id_str; | |
169 int worker_process_host_id; | |
170 int worker_route_id; | |
171 CHECK(args->GetSize() == 2); | |
172 CHECK(args->GetString(0, &worker_process_host_id_str)); | |
173 CHECK(args->GetString(1, &worker_route_id_str)); | |
174 CHECK(base::StringToInt(worker_process_host_id_str, | |
175 &worker_process_host_id)); | |
176 CHECK(base::StringToInt(worker_route_id_str, &worker_route_id)); | |
177 | |
178 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
179 base::Bind(&TerminateWorker, worker_process_host_id, worker_route_id)); | |
180 } | |
181 | |
182 } // namespace | |
183 | |
184 class WorkersUI::WorkerCreationDestructionListener | |
185 : public WorkerServiceObserver, | |
186 public base::RefCountedThreadSafe<WorkerCreationDestructionListener> { | |
187 public: | |
188 explicit WorkerCreationDestructionListener(WorkersUI* workers_ui) | |
189 : workers_ui_(workers_ui) { | |
190 BrowserThread::PostTask( | |
191 BrowserThread::IO, FROM_HERE, | |
192 base::Bind(&WorkerCreationDestructionListener::RegisterObserver, | |
193 this)); | |
194 } | |
195 | |
196 void WorkersUIDestroyed() { | |
197 workers_ui_ = NULL; | |
198 BrowserThread::PostTask( | |
199 BrowserThread::IO, FROM_HERE, | |
200 base::Bind(&WorkerCreationDestructionListener::UnregisterObserver, | |
201 this)); | |
202 } | |
203 | |
204 private: | |
205 friend class base::RefCountedThreadSafe<WorkerCreationDestructionListener>; | |
206 virtual ~WorkerCreationDestructionListener() { | |
207 } | |
208 | |
209 virtual void WorkerCreated( | |
210 const GURL& url, | |
211 const string16& name, | |
212 int process_id, | |
213 int route_id) OVERRIDE { | |
214 BrowserThread::PostTask( | |
215 BrowserThread::UI, FROM_HERE, | |
216 base::Bind(&WorkerCreationDestructionListener::NotifyWorkerCreated, | |
217 this, | |
218 base::Owned(BuildWorkerData(url, name, process_id, route_id, | |
219 base::kNullProcessHandle)))); | |
220 } | |
221 virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE { | |
222 DictionaryValue* worker_data = new DictionaryValue(); | |
223 worker_data->SetInteger(kWorkerProcessHostIdField, process_id); | |
224 worker_data->SetInteger(kWorkerRouteIdField, route_id); | |
225 | |
226 BrowserThread::PostTask( | |
227 BrowserThread::UI, FROM_HERE, | |
228 base::Bind(&WorkerCreationDestructionListener::NotifyWorkerDestroyed, | |
229 this, base::Owned(worker_data))); | |
230 } | |
231 | |
232 void NotifyWorkerCreated(DictionaryValue* worker_data) { | |
233 if (workers_ui_) { | |
234 workers_ui_->web_ui()->CallJavascriptFunction( | |
235 "workerCreated", *worker_data); | |
236 } | |
237 } | |
238 | |
239 void NotifyWorkerDestroyed(DictionaryValue* worker_data) { | |
240 if (workers_ui_) { | |
241 workers_ui_->web_ui()->CallJavascriptFunction( | |
242 "workerDestroyed", *worker_data); | |
243 } | |
244 } | |
245 | |
246 void RegisterObserver() { | |
247 WorkerService::GetInstance()->AddObserver(this); | |
248 } | |
249 void UnregisterObserver() { | |
250 WorkerService::GetInstance()->RemoveObserver(this); | |
251 } | |
252 | |
253 WorkersUI* workers_ui_; | |
254 }; | |
255 | |
256 WorkersUI::WorkersUI(content::WebUI* web_ui) | |
257 : WebUIController(web_ui), | |
258 observer_(new WorkerCreationDestructionListener(this)){ | |
259 web_ui->AddMessageHandler(new WorkersDOMHandler()); | |
260 | |
261 WorkersUIHTMLSource* html_source = new WorkersUIHTMLSource(); | |
262 | |
263 // Set up the chrome://workers/ source. | |
264 Profile* profile = Profile::FromWebUI(web_ui); | |
265 profile->GetChromeURLDataManager()->AddDataSource(html_source); | |
266 } | |
267 | |
268 WorkersUI::~WorkersUI() { | |
269 observer_->WorkersUIDestroyed(); | |
270 observer_ = NULL; | |
271 } | |
OLD | NEW |