Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: content/browser/service_worker/service_worker_internals_ui.cc

Issue 182383008: Create chrome://serviceworker-internals (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix GetInfo / const stuff Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014 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/service_worker/service_worker_internals_ui.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/values.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_context_wrapper.h"
14 #include "content/browser/service_worker/service_worker_registration.h"
15 #include "content/browser/service_worker/service_worker_version.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/storage_partition.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/browser/web_ui.h"
21 #include "content/public/browser/web_ui_data_source.h"
22 #include "content/public/common/url_constants.h"
23 #include "grit/content_resources.h"
24
25 using base::DictionaryValue;
26 using base::FundamentalValue;
27 using base::ListValue;
28 using base::StringValue;
29 using base::Value;
30 using base::WeakPtr;
31
32 namespace content {
33
34 // This class, and the parameters to the *IOTHread methods should be
35 // created on the UI thread, where it will delete itself and
36 // those values.
michaeln 2014/03/06 01:19:02 comment seems stale
alecflett 2014/03/06 19:25:15 nope.. the operation eventually proxies itself bac
michaeln 2014/03/06 19:54:15 But it doesn't "delete itself" and see other comme
37 class ServiceWorkerInternalsUI::OperationProxy
38 : public base::RefCountedThreadSafe<
39 ServiceWorkerInternalsUI::OperationProxy> {
40 public:
41 OperationProxy(const WeakPtr<ServiceWorkerInternalsUI> internals,
42 scoped_ptr<ListValue> original_args)
43 : internals_(internals), original_args_(original_args.Pass()) {}
44
45 void GetRegistrationsOnIOThread(ServiceWorkerContextWrapper* context,
46 const base::FilePath& context_path);
47 void UnregisterOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,
48 const GURL& scope);
49 void StartWorkerOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,
50 const GURL& scope);
51 void StopWorkerOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,
52 const GURL& scope);
53
54 private:
55 friend class base::RefCountedThreadSafe<
56 ServiceWorkerInternalsUI::OperationProxy>;
57 ~OperationProxy() {}
58 void OnHaveRegistrations(
59 const base::FilePath& context_path,
60 const std::vector<ServiceWorkerRegistrationInfo>& registrations);
61
62 void OperationComplete(ServiceWorkerStatusCode status);
63
64 void StartActiveWorker(
65 ServiceWorkerStatusCode status,
66 const scoped_refptr<ServiceWorkerRegistration>& registration);
67
68 void StopActiveWorker(
69 ServiceWorkerStatusCode status,
70 const scoped_refptr<ServiceWorkerRegistration>& registration);
71
72 WeakPtr<ServiceWorkerInternalsUI> internals_;
73 scoped_ptr<ListValue> original_args_;
michaeln 2014/03/06 01:19:02 I'm not so familiar with ListValue, does it matter
alecflett 2014/03/06 19:25:15 They're deleted on the UI thread, where they're cr
michaeln 2014/03/06 19:54:15 Thats typically what will happen given how its use
74 };
75
76 ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui)
77 : WebUIController(web_ui) {
78 WebUIDataSource* source =
79 WebUIDataSource::Create(kChromeUIServiceWorkerInternalsHost);
80 source->SetUseJsonJSFormatV2();
81 source->SetJsonPath("strings.js");
82 source->AddResourcePath("serviceworker_internals.js",
83 IDR_SERVICE_WORKER_INTERNALS_JS);
84 source->AddResourcePath("serviceworker_internals.css",
85 IDR_SERVICE_WORKER_INTERNALS_CSS);
86 source->SetDefaultResource(IDR_SERVICE_WORKER_INTERNALS_HTML);
87
88 BrowserContext* browser_context =
89 web_ui->GetWebContents()->GetBrowserContext();
90 WebUIDataSource::Add(browser_context, source);
91
92 web_ui->RegisterMessageCallback(
93 "getAllRegistrations",
94 base::Bind(&ServiceWorkerInternalsUI::GetAllRegistrations,
95 base::Unretained(this)));
96 web_ui->RegisterMessageCallback(
97 "start",
98 base::Bind(&ServiceWorkerInternalsUI::StartWorker,
99 base::Unretained(this)));
100 web_ui->RegisterMessageCallback(
101 "stop",
102 base::Bind(&ServiceWorkerInternalsUI::StopWorker,
103 base::Unretained(this)));
104 web_ui->RegisterMessageCallback(
105 "unregister",
106 base::Bind(&ServiceWorkerInternalsUI::Unregister,
107 base::Unretained(this)));
108 }
109
110 ServiceWorkerInternalsUI::~ServiceWorkerInternalsUI() {}
111
112 void ServiceWorkerInternalsUI::GetAllRegistrations(const ListValue* args) {
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114
115 BrowserContext* browser_context =
116 web_ui()->GetWebContents()->GetBrowserContext();
117
118 // Safe to use base::Unretained(this) because
119 // ForEachStoragePartition is synchronous.
120 BrowserContext::StoragePartitionCallback cb =
121 base::Bind(&ServiceWorkerInternalsUI::AddContextFromStoragePartition,
122 base::Unretained(this));
123 BrowserContext::ForEachStoragePartition(browser_context, cb);
124 }
125
126 void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
127 StoragePartition* partition) {
128 scoped_refptr<ServiceWorkerContextWrapper> context =
129 partition->GetServiceWorkerContext();
130 BrowserThread::PostTask(
131 BrowserThread::IO,
132 FROM_HERE,
133 base::Bind(
134 &ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread,
135 new OperationProxy(AsWeakPtr(), scoped_ptr<ListValue>()),
136 context,
137 partition->GetPath()));
138 }
139
140 namespace {
141 void FindContext(const base::FilePath& partition_path,
142 StoragePartition** result_partition,
143 scoped_refptr<ServiceWorkerContextWrapper>* result_context,
144 StoragePartition* storage_partition) {
145 if (storage_partition->GetPath() == partition_path) {
146 *result_partition = storage_partition;
147 *result_context = storage_partition->GetServiceWorkerContext();
148 }
149 }
150 } // namespace
151
152 bool ServiceWorkerInternalsUI::GetRegistrationInfo(
153 const ListValue* args,
154 base::FilePath* partition_path,
155 GURL* scope,
156 scoped_refptr<ServiceWorkerContextWrapper>* context) const {
157 base::FilePath::StringType path_string;
158 if (!args->GetString(0, &path_string))
159 return false;
160 *partition_path = base::FilePath(path_string);
161
162 std::string scope_string;
163 if (!args->GetString(1, &scope_string))
164 return false;
165 *scope = GURL(scope_string);
166
167 BrowserContext* browser_context =
168 web_ui()->GetWebContents()->GetBrowserContext();
169
170 StoragePartition* result_partition(NULL);
171 BrowserContext::StoragePartitionCallback cb =
172 base::Bind(&FindContext, *partition_path, &result_partition, context);
173 BrowserContext::ForEachStoragePartition(browser_context, cb);
174
175 if (!result_partition || !(*context))
176 return false;
177
178 return true;
179 }
180
181 void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
183 base::FilePath partition_path;
184 GURL scope;
185 scoped_refptr<ServiceWorkerContextWrapper> context;
186 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
187 return;
188
189 scoped_ptr<ListValue> args_copy(args->DeepCopy());
190 BrowserThread::PostTask(
191 BrowserThread::IO,
192 FROM_HERE,
193 base::Bind(
194 &ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread,
195 new OperationProxy(AsWeakPtr(), args_copy.Pass()),
196 context,
197 scope));
198 }
199
200 void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
202 base::FilePath partition_path;
203 GURL scope;
204 scoped_refptr<ServiceWorkerContextWrapper> context;
205 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
206 return;
207
208 scoped_ptr<ListValue> args_copy(args->DeepCopy());
209 BrowserThread::PostTask(
210 BrowserThread::IO,
211 FROM_HERE,
212 base::Bind(
213 &ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread,
214 new OperationProxy(AsWeakPtr(), args_copy.Pass()),
215 context,
216 scope));
217 }
218
219 void ServiceWorkerInternalsUI::StopWorker(const ListValue* args) {
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
221 base::FilePath partition_path;
222 GURL scope;
223 scoped_refptr<ServiceWorkerContextWrapper> context;
224 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
225 return;
226
227 scoped_ptr<ListValue> args_copy(args->DeepCopy());
228 BrowserThread::PostTask(
229 BrowserThread::IO,
230 FROM_HERE,
231 base::Bind(
232 &ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread,
233 new OperationProxy(AsWeakPtr(), args_copy.Pass()),
234 context,
235 scope));
236 }
237
238 void ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread(
239 ServiceWorkerContextWrapper* context,
240 const base::FilePath& context_path) {
241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
242
243 context->context()->storage()->GetAllRegistrations(
244 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
245 this,
246 context_path));
247 }
248
249 void ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread(
250 scoped_refptr<ServiceWorkerContextWrapper> context,
251 const GURL& scope) {
252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
253 context->context()->UnregisterServiceWorker(
254 scope,
255 0, // render process id?
256 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
257 this));
258 }
259
260 void ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread(
261 scoped_refptr<ServiceWorkerContextWrapper> context,
262 const GURL& scope) {
263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
264 // TODO(alecflett): Add support for starting/stopping workers for
265 // pending versions too.
266 context->context()->storage()->FindRegistrationForPattern(
267 scope,
268 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StartActiveWorker,
269 this));
270 }
271
272 void ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread(
273 scoped_refptr<ServiceWorkerContextWrapper> context,
274 const GURL& scope) {
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
276 // TODO(alecflett): Add support for starting/stopping workers for
277 // pending versions too.
278 context->context()->storage()->FindRegistrationForPattern(
279 scope,
280 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker,
281 this));
282 }
283
284 namespace {
285 void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
286 DictionaryValue* info) {
287 switch (version.status) {
288 case ServiceWorkerVersion::STOPPED:
289 info->SetString("status", "STOPPED");
290 break;
291 case EmbeddedWorkerInstance::STARTING:
292 info->SetString("status", "STARTING");
293 break;
294 case EmbeddedWorkerInstance::RUNNING:
295 info->SetString("status", "RUNNING");
296 break;
297 case EmbeddedWorkerInstance::STOPPING:
298 info->SetString("status", "STOPPING");
299 break;
300 }
301
302 info->SetInteger("process_id", version.process_id);
303 // is this hardware thread or internal thread?
304 info->SetInteger("thread_id", version.thread_id);
305 }
306 } // namespace
307
308 void ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations(
309 const base::FilePath& context_path,
310 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
311 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
312 BrowserThread::PostTask(
michaeln 2014/03/06 19:54:15 fyi: OnHaveRegistrations may have been run on the
313 BrowserThread::UI,
314 FROM_HERE,
315 base::Bind(
316 &ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
317 this,
318 context_path,
319 registrations));
320 return;
321 }
322
323 ListValue result;
324 for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it =
325 registrations.begin();
326 it != registrations.end();
327 ++it) {
328 const ServiceWorkerRegistrationInfo& registration = *it;
329 DictionaryValue* registration_info = new DictionaryValue();
330 registration_info->SetString("scope", registration.pattern.spec());
331 registration_info->SetString("script_url", registration.script_url.spec());
332
333 if (!registration.active_version.is_null) {
334 DictionaryValue* active_info = new DictionaryValue();
335 UpdateVersionInfo(registration.active_version, active_info);
336 registration_info->Set("active", active_info);
337 }
338
339 if (!registration.pending_version.is_null) {
340 DictionaryValue* pending_info = new DictionaryValue();
341 UpdateVersionInfo(registration.active_version, pending_info);
342 registration_info->Set("pending", pending_info);
343 }
344
345 result.Append(registration_info);
346 }
347
348 if (internals_)
349 internals_->web_ui()->CallJavascriptFunction(
350 "serviceworker.onPartitionData",
351 result,
352 StringValue(context_path.value()));
353 }
354
355 void ServiceWorkerInternalsUI::OperationProxy::OperationComplete(
356 ServiceWorkerStatusCode status) {
357 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
358 BrowserThread::PostTask(
359 BrowserThread::UI,
360 FROM_HERE,
361 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
362 this,
363 status));
364 return;
365 }
366
367 original_args_->Insert(0, new FundamentalValue(static_cast<int>(status)));
368 if (internals_)
369 internals_->web_ui()->CallJavascriptFunction(
370 "serviceworker.onOperationComplete",
371 std::vector<const Value*>(original_args_->begin(),
372 original_args_->end()));
373 }
374
375 void ServiceWorkerInternalsUI::OperationProxy::StartActiveWorker(
376 ServiceWorkerStatusCode status,
377 const scoped_refptr<ServiceWorkerRegistration>& registration) {
378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
379 if (status == SERVICE_WORKER_OK) {
380 registration->active_version()->StartWorker(base::Bind(
381 &ServiceWorkerInternalsUI::OperationProxy::OperationComplete, this));
382 return;
383 }
384
385 OperationComplete(status);
386 }
387
388 void ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker(
389 ServiceWorkerStatusCode status,
390 const scoped_refptr<ServiceWorkerRegistration>& registration) {
391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
392 if (status == SERVICE_WORKER_OK) {
393 registration->active_version()->StopWorker(base::Bind(
394 &ServiceWorkerInternalsUI::OperationProxy::OperationComplete, this));
395 return;
396 }
397
398 OperationComplete(status);
399 }
400
401 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698