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

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: Allow deletion on any thread 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 proxies calls to the ServiceWorker APIs on the IO
35 // thread, and then calls back JavaScript on the UI thread. It deletes
36 // itself when complete.
michaeln 2014/03/06 23:31:49 nit: the "it deletes itself" comment is more confu
alecflett 2014/03/06 23:46:47 Done.
37 class ServiceWorkerInternalsUI::OperationProxy
38 : public base::RefCountedThreadSafe<
39 ServiceWorkerInternalsUI::OperationProxy> {
michaeln 2014/03/06 23:31:49 nit: indent is off
alecflett 2014/03/06 23:46:47 Done.
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<OperationProxy>;
56 ~OperationProxy() {}
57 void OnHaveRegistrations(
58 const base::FilePath& context_path,
59 const std::vector<ServiceWorkerRegistrationInfo>& registrations);
60
61 void OperationComplete(ServiceWorkerStatusCode status);
62
63 void StartActiveWorker(
64 ServiceWorkerStatusCode status,
65 const scoped_refptr<ServiceWorkerRegistration>& registration);
66
67 void StopActiveWorker(
68 ServiceWorkerStatusCode status,
69 const scoped_refptr<ServiceWorkerRegistration>& registration);
70
71 WeakPtr<ServiceWorkerInternalsUI> internals_;
72 scoped_ptr<ListValue> original_args_;
73 };
74
75 ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui)
76 : WebUIController(web_ui) {
77 WebUIDataSource* source =
78 WebUIDataSource::Create(kChromeUIServiceWorkerInternalsHost);
79 source->SetUseJsonJSFormatV2();
80 source->SetJsonPath("strings.js");
81 source->AddResourcePath("serviceworker_internals.js",
82 IDR_SERVICE_WORKER_INTERNALS_JS);
83 source->AddResourcePath("serviceworker_internals.css",
84 IDR_SERVICE_WORKER_INTERNALS_CSS);
85 source->SetDefaultResource(IDR_SERVICE_WORKER_INTERNALS_HTML);
86
87 BrowserContext* browser_context =
88 web_ui->GetWebContents()->GetBrowserContext();
89 WebUIDataSource::Add(browser_context, source);
90
91 web_ui->RegisterMessageCallback(
92 "getAllRegistrations",
93 base::Bind(&ServiceWorkerInternalsUI::GetAllRegistrations,
94 base::Unretained(this)));
95 web_ui->RegisterMessageCallback(
96 "start",
97 base::Bind(&ServiceWorkerInternalsUI::StartWorker,
98 base::Unretained(this)));
99 web_ui->RegisterMessageCallback(
100 "stop",
101 base::Bind(&ServiceWorkerInternalsUI::StopWorker,
102 base::Unretained(this)));
103 web_ui->RegisterMessageCallback(
104 "unregister",
105 base::Bind(&ServiceWorkerInternalsUI::Unregister,
106 base::Unretained(this)));
107 }
108
109 ServiceWorkerInternalsUI::~ServiceWorkerInternalsUI() {}
110
111 void ServiceWorkerInternalsUI::GetAllRegistrations(const ListValue* args) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113
114 BrowserContext* browser_context =
115 web_ui()->GetWebContents()->GetBrowserContext();
116
117 // Safe to use base::Unretained(this) because
118 // ForEachStoragePartition is synchronous.
119 BrowserContext::StoragePartitionCallback cb =
120 base::Bind(&ServiceWorkerInternalsUI::AddContextFromStoragePartition,
121 base::Unretained(this));
122 BrowserContext::ForEachStoragePartition(browser_context, cb);
123 }
124
125 void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
126 StoragePartition* partition) {
127 scoped_refptr<ServiceWorkerContextWrapper> context =
128 partition->GetServiceWorkerContext();
129 BrowserThread::PostTask(
130 BrowserThread::IO,
131 FROM_HERE,
132 base::Bind(
133 &ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread,
134 new OperationProxy(AsWeakPtr(), scoped_ptr<ListValue>()),
135 context,
136 partition->GetPath()));
137 }
138
139 namespace {
140 void FindContext(const base::FilePath& partition_path,
141 StoragePartition** result_partition,
142 scoped_refptr<ServiceWorkerContextWrapper>* result_context,
143 StoragePartition* storage_partition) {
144 if (storage_partition->GetPath() == partition_path) {
145 *result_partition = storage_partition;
146 *result_context = storage_partition->GetServiceWorkerContext();
147 }
148 }
149 } // namespace
150
151 bool ServiceWorkerInternalsUI::GetRegistrationInfo(
152 const ListValue* args,
153 base::FilePath* partition_path,
154 GURL* scope,
155 scoped_refptr<ServiceWorkerContextWrapper>* context) const {
156 base::FilePath::StringType path_string;
157 if (!args->GetString(0, &path_string))
158 return false;
159 *partition_path = base::FilePath(path_string);
160
161 std::string scope_string;
162 if (!args->GetString(1, &scope_string))
163 return false;
164 *scope = GURL(scope_string);
165
166 BrowserContext* browser_context =
167 web_ui()->GetWebContents()->GetBrowserContext();
168
169 StoragePartition* result_partition(NULL);
170 BrowserContext::StoragePartitionCallback cb =
171 base::Bind(&FindContext, *partition_path, &result_partition, context);
172 BrowserContext::ForEachStoragePartition(browser_context, cb);
173
174 if (!result_partition || !(*context))
175 return false;
176
177 return true;
178 }
179
180 void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
182 base::FilePath partition_path;
183 GURL scope;
184 scoped_refptr<ServiceWorkerContextWrapper> context;
185 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
186 return;
187
188 scoped_ptr<ListValue> args_copy(args->DeepCopy());
189 BrowserThread::PostTask(
190 BrowserThread::IO,
191 FROM_HERE,
192 base::Bind(
193 &ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread,
194 new OperationProxy(AsWeakPtr(), args_copy.Pass()),
195 context,
196 scope));
197 }
198
199 void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
201 base::FilePath partition_path;
202 GURL scope;
203 scoped_refptr<ServiceWorkerContextWrapper> context;
204 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
205 return;
206
207 scoped_ptr<ListValue> args_copy(args->DeepCopy());
208 BrowserThread::PostTask(
209 BrowserThread::IO,
210 FROM_HERE,
211 base::Bind(
212 &ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread,
213 new OperationProxy(AsWeakPtr(), args_copy.Pass()),
214 context,
215 scope));
216 }
217
218 void ServiceWorkerInternalsUI::StopWorker(const ListValue* args) {
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
220 base::FilePath partition_path;
221 GURL scope;
222 scoped_refptr<ServiceWorkerContextWrapper> context;
223 if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
224 return;
225
226 scoped_ptr<ListValue> args_copy(args->DeepCopy());
227 BrowserThread::PostTask(
228 BrowserThread::IO,
229 FROM_HERE,
230 base::Bind(
231 &ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread,
232 new OperationProxy(AsWeakPtr(), args_copy.Pass()),
233 context,
234 scope));
235 }
236
237 void ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread(
238 ServiceWorkerContextWrapper* context,
239 const base::FilePath& context_path) {
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241
242 context->context()->storage()->GetAllRegistrations(
243 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
244 this,
245 context_path));
246 }
247
248 void ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread(
249 scoped_refptr<ServiceWorkerContextWrapper> context,
250 const GURL& scope) {
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
252 context->context()->UnregisterServiceWorker(
253 scope,
254 0, // render process id?
255 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
256 this));
257 }
258
259 void ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread(
260 scoped_refptr<ServiceWorkerContextWrapper> context,
261 const GURL& scope) {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
263 // TODO(alecflett): Add support for starting/stopping workers for
264 // pending versions too.
265 context->context()->storage()->FindRegistrationForPattern(
266 scope,
267 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StartActiveWorker,
268 this));
269 }
270
271 void ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread(
272 scoped_refptr<ServiceWorkerContextWrapper> context,
273 const GURL& scope) {
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
275 // TODO(alecflett): Add support for starting/stopping workers for
276 // pending versions too.
277 context->context()->storage()->FindRegistrationForPattern(
278 scope,
279 base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker,
280 this));
281 }
282
283 namespace {
284 void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
285 DictionaryValue* info) {
286 switch (version.status) {
287 case ServiceWorkerVersion::STOPPED:
288 info->SetString("status", "STOPPED");
289 break;
290 case EmbeddedWorkerInstance::STARTING:
291 info->SetString("status", "STARTING");
292 break;
293 case EmbeddedWorkerInstance::RUNNING:
294 info->SetString("status", "RUNNING");
295 break;
296 case EmbeddedWorkerInstance::STOPPING:
297 info->SetString("status", "STOPPING");
298 break;
299 }
300
301 info->SetInteger("process_id", version.process_id);
302 // is this hardware thread or internal thread?
303 info->SetInteger("thread_id", version.thread_id);
304 }
305 } // namespace
306
307 void ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations(
308 const base::FilePath& context_path,
309 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
310 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
311 BrowserThread::PostTask(
312 BrowserThread::UI,
313 FROM_HERE,
314 base::Bind(
315 &ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
316 this,
317 context_path,
318 registrations));
319 return;
320 }
321
322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
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(
michaeln 2014/03/06 23:31:49 nit: Maybe only do this part if the partition actu
alecflett 2014/03/06 23:46:47 Done.
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 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
368 original_args_->Insert(0, new FundamentalValue(static_cast<int>(status)));
369 if (internals_)
370 internals_->web_ui()->CallJavascriptFunction(
371 "serviceworker.onOperationComplete",
372 std::vector<const Value*>(original_args_->begin(),
373 original_args_->end()));
374 }
375
376 void ServiceWorkerInternalsUI::OperationProxy::StartActiveWorker(
377 ServiceWorkerStatusCode status,
378 const scoped_refptr<ServiceWorkerRegistration>& registration) {
379 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
380 if (status == SERVICE_WORKER_OK) {
381 registration->active_version()->StartWorker(base::Bind(
382 &ServiceWorkerInternalsUI::OperationProxy::OperationComplete, this));
383 return;
384 }
385
386 OperationComplete(status);
387 }
388
389 void ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker(
390 ServiceWorkerStatusCode status,
391 const scoped_refptr<ServiceWorkerRegistration>& registration) {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
393 if (status == SERVICE_WORKER_OK) {
394 registration->active_version()->StopWorker(base::Bind(
395 &ServiceWorkerInternalsUI::OperationProxy::OperationComplete, this));
396 return;
397 }
398
399 OperationComplete(status);
400 }
401
402 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698