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

Side by Side Diff: extensions/browser/service_worker_manager.cc

Issue 182253010: Register a Service Worker when an extension is enabled. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Roughly wire things up and add a test 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 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 "extensions/browser/service_worker_manager.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "components/browser_context_keyed_service/browser_context_dependency_ma nager.h"
10 #include "content/browser/service_worker/service_worker_context_core.h"
11 #include "content/browser/service_worker/service_worker_context_wrapper.h"
12 #include "content/public/browser/browser_context.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/storage_partition.h"
15 #include "extensions/browser/extensions_browser_client.h"
16 #include "extensions/common/manifest_handlers/background_info.h"
17
18 namespace extensions {
19
20 using base::Callback;
21 using base::Closure;
22 using base::WeakPtr;
23 using content::BrowserContext;
24 using content::BrowserThread;
25 using content::ServiceWorkerStatusCode;
26
27 static const char* CurrentBrowserThreadName() {
28 BrowserThread::ID id;
29 if (BrowserThread::GetCurrentThreadIdentifier(&id)) {
30 switch (id) {
31 case BrowserThread::UI:
32 return "UI";
33 case BrowserThread::DB:
34 return "DB";
35 case BrowserThread::FILE:
36 return "FILE";
37 case BrowserThread::FILE_USER_BLOCKING:
38 return "FILE_USER_BLOCKING";
39 case BrowserThread::PROCESS_LAUNCHER:
40 return "PROCESS_LAUNCHER";
41 case BrowserThread::CACHE:
42 return "CACHE";
43 case BrowserThread::IO:
44 return "IO";
45 default:
46 break;
47 }
48 }
49 return "Unknown";
50 }
51
52 static void DCheckCurrentlyOn(BrowserThread::ID thread) {
53 DCHECK(BrowserThread::CurrentlyOn(thread)) << CurrentBrowserThreadName();
scheib 2014/03/10 21:31:38 Maybe base::MessageLoop::current()->thread_name();
54 }
55
56 ServiceWorkerManager::State::State() {}
57 ServiceWorkerManager::State::~State() {}
58
59 ServiceWorkerManager::ServiceWorkerManager(BrowserContext* context)
60 : context_(context), weak_this_factory_(this) {}
61 ServiceWorkerManager::~ServiceWorkerManager() {}
62
63 ServiceWorkerManager* ServiceWorkerManager::Get(
64 content::BrowserContext* context) {
65 return ServiceWorkerManagerFactory::GetForBrowserContext(context);
66 }
67
68 content::StoragePartition* ServiceWorkerManager::GetStoragePartition(
69 const Extension* ext) const {
70 return content::BrowserContext::GetStoragePartitionForSite(
71 context_, Extension::GetBaseURLFromExtensionId(ext->id()));
72 }
73
74 scoped_refptr<content::ServiceWorkerContextWrapper>
75 ServiceWorkerManager::GetSWContext(const Extension* ext) const {
76 return GetStoragePartition(ext)->GetServiceWorkerContext();
77 }
78
79 template <typename Arg1>
80 static void RunCallback1(const Callback<void(Arg1)>& callback,
81 const Arg1& arg1) {
82 callback.Run(arg1);
83 }
84
85 static void FinishRegister(
86 const Callback<void(ServiceWorkerStatusCode)>& continuation,
87 content::ServiceWorkerStatusCode status,
88 int64 registration_id) {
89 DCheckCurrentlyOn(BrowserThread::IO);
90 BrowserThread::PostTask(
91 BrowserThread::UI,
92 FROM_HERE,
93 base::Bind(&RunCallback1<ServiceWorkerStatusCode>, continuation, status));
kinuko 2014/03/10 07:03:19 nit: why don't we just do base::Bind(continuation,
94 }
95
96 static void DoRegister(
97 const scoped_refptr<content::ServiceWorkerContextWrapper>&
98 service_worker_context,
99 const ExtensionId& extension_id,
100 const GURL& service_worker_script,
101 const Callback<void(ServiceWorkerStatusCode)>& continuation) {
102 DCheckCurrentlyOn(BrowserThread::IO);
103 service_worker_context->context()->RegisterServiceWorker(
104 Extension::GetBaseURLFromExtensionId(extension_id).Resolve("/*"),
105 service_worker_script,
106 -1,
107 base::Bind(&FinishRegister, continuation));
108 }
109
110 // alecflett says that if we send a series of RegisterServiceWorker and
111 // UnregisterServiceWorker calls to a ServiceWorkerContextCore, we're guaranteed
112 // that the callbacks come back in the same order, and that the last one will be
michaeln 2014/03/10 22:15:03 That order is guaranteed for the same 'scope', but
113 // the final state.
114 void ServiceWorkerManager::RegisterExtension(const Extension* extension) {
115 DCheckCurrentlyOn(BrowserThread::UI);
116 CHECK(BackgroundInfo::HasServiceWorker(extension));
117 State& ext_state = states_[extension->id()];
118 if (ext_state.registration == REGISTERING ||
119 ext_state.registration == REGISTERED)
120 return;
121 ext_state.registration = REGISTERING;
122 ++ext_state.outstanding_state_changes;
123 BrowserThread::PostTask(
124 BrowserThread::IO,
125 FROM_HERE,
126 base::Bind(&DoRegister,
127 GetSWContext(extension),
128 extension->id(),
129 extension->GetResourceURL(
130 BackgroundInfo::GetServiceWorkerScript(extension)),
131 base::Bind(&ServiceWorkerManager::FinishRegistration,
132 WeakThis(),
133 extension->id())));
134 }
135
136 void ServiceWorkerManager::FinishRegistration(const ExtensionId& extension_id,
137 ServiceWorkerStatusCode result) {
138 DCheckCurrentlyOn(BrowserThread::UI);
139 State& ext_state = states_[extension_id];
140 --ext_state.outstanding_state_changes;
141 DCHECK_GE(ext_state.outstanding_state_changes, 0);
142 if (ext_state.outstanding_state_changes > 0)
143 return;
144
145 DCHECK_EQ(ext_state.registration, REGISTERING);
146 std::vector<Closure> to_run;
147 switch (result) {
148 case content::SERVICE_WORKER_OK:
149 ext_state.registration = REGISTERED;
150 to_run.swap(ext_state.registration_succeeded);
151 ext_state.registration_failed.clear();
152 break;
153 default:
154 LOG(ERROR) << "Service Worker Registration failed for extension "
155 << extension_id << ": "
156 << content::ServiceWorkerStatusToString(result);
157 to_run.swap(ext_state.registration_failed);
158 states_.erase(extension_id);
159 break;
160 }
161
162 for (size_t i = 0; i < to_run.size(); ++i) {
163 to_run[i].Run();
164 }
165 }
166
167 static void FinishUnregister(
168 const Callback<void(ServiceWorkerStatusCode)>& continuation,
169 content::ServiceWorkerStatusCode status) {
170 DCheckCurrentlyOn(BrowserThread::IO);
171 BrowserThread::PostTask(
172 BrowserThread::UI,
173 FROM_HERE,
174 base::Bind(&RunCallback1<ServiceWorkerStatusCode>, continuation, status));
175 }
176
177 static void DoUnregister(
178 const scoped_refptr<content::ServiceWorkerContextWrapper>&
179 service_worker_context,
180 const ExtensionId& extension_id,
181 const Callback<void(ServiceWorkerStatusCode)>& continuation) {
182 DCheckCurrentlyOn(BrowserThread::IO);
183 service_worker_context->context()->UnregisterServiceWorker(
184 Extension::GetBaseURLFromExtensionId(extension_id).Resolve("/*"),
185 -1,
186 base::Bind(&FinishUnregister, continuation));
187 }
188
189 void ServiceWorkerManager::UnregisterExtension(const Extension* extension) {
190 DCheckCurrentlyOn(BrowserThread::UI);
191 CHECK(BackgroundInfo::HasServiceWorker(extension));
192
193 base::hash_map<ExtensionId, State>::iterator it =
194 states_.find(extension->id());
195 if (it == states_.end()) {
196 // Extension isn't registered.
197 return;
198 }
199 State& ext_state = it->second;
200 if (ext_state.registration == UNREGISTERING)
201 return;
202
203 ext_state.registration = UNREGISTERING;
204 ++ext_state.outstanding_state_changes;
205 BrowserThread::PostTask(
206 BrowserThread::IO,
207 FROM_HERE,
208 base::Bind(&DoUnregister,
209 GetSWContext(extension),
210 extension->id(),
211 base::Bind(&ServiceWorkerManager::FinishUnregistration,
212 WeakThis(),
213 extension->id())));
214 }
215
216 void ServiceWorkerManager::FinishUnregistration(
217 const ExtensionId& extension_id,
218 ServiceWorkerStatusCode result) {
219 DCheckCurrentlyOn(BrowserThread::UI);
220 State& ext_state = states_[extension_id];
221 --ext_state.outstanding_state_changes;
222 DCHECK_GE(ext_state.outstanding_state_changes, 0);
223 if (ext_state.outstanding_state_changes > 0)
224 return;
225
226 DCHECK_EQ(ext_state.registration, UNREGISTERING);
227 std::vector<Closure> to_run;
228 switch (result) {
229 case content::SERVICE_WORKER_OK:
230 to_run.swap(ext_state.unregistration_succeeded);
231 states_.erase(extension_id);
232 break;
233 default:
234 LOG(ERROR) << "Service Worker Unregistration failed for extension "
235 << extension_id << ": "
236 << content::ServiceWorkerStatusToString(result);
237 ext_state.registration = REGISTERED;
238 to_run.swap(ext_state.unregistration_failed);
239 ext_state.unregistration_succeeded.clear();
240 break;
241 }
242
243 for (size_t i = 0; i < to_run.size(); ++i) {
244 to_run[i].Run();
245 }
246 }
247
248 WeakPtr<ServiceWorkerManager> ServiceWorkerManager::WeakThis() {
249 return weak_this_factory_.GetWeakPtr();
250 }
251
252 // ServiceWorkerManagerFactory
253
254 ServiceWorkerManager* ServiceWorkerManagerFactory::GetForBrowserContext(
255 content::BrowserContext* context) {
256 return static_cast<ServiceWorkerManager*>(
257 GetInstance()->GetServiceForBrowserContext(context, true));
258 }
259
260 ServiceWorkerManagerFactory* ServiceWorkerManagerFactory::GetInstance() {
261 return Singleton<ServiceWorkerManagerFactory>::get();
262 }
263
264 void ServiceWorkerManagerFactory::SetInstanceForTesting(
265 content::BrowserContext* context,
266 ServiceWorkerManager* manager) {
267 Associate(context, manager);
268 }
269
270 ServiceWorkerManagerFactory::ServiceWorkerManagerFactory()
271 : BrowserContextKeyedServiceFactory(
272 "ServiceWorkerManager",
273 BrowserContextDependencyManager::GetInstance()) {}
274
275 ServiceWorkerManagerFactory::~ServiceWorkerManagerFactory() {}
276
277 BrowserContextKeyedService*
278 ServiceWorkerManagerFactory::BuildServiceInstanceFor(
279 content::BrowserContext* context) const {
280 return new ServiceWorkerManager(context);
281 }
282
283 // TODO(jyasskin): Deal with incognito mode.
284 content::BrowserContext* ServiceWorkerManagerFactory::GetBrowserContextToUse(
285 content::BrowserContext* context) const {
286 return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
287 }
288
289 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698