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

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: Sync to r261176 Created 6 years, 8 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/keyed_service/content/browser_context_dependency_manager.h"
10 #include "content/public/browser/browser_context.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/render_process_host.h"
13 #include "content/public/browser/service_worker_context.h"
14 #include "content/public/browser/storage_partition.h"
15 #include "extensions/browser/extension_host.h"
16 #include "extensions/browser/extension_system.h"
17 #include "extensions/browser/extensions_browser_client.h"
18 #include "extensions/browser/process_manager.h"
19 #include "extensions/common/manifest_handlers/background_info.h"
20
21 namespace extensions {
22
23 using base::Callback;
24 using base::Closure;
25 using base::WeakPtr;
26 using content::BrowserContext;
27 using content::BrowserThread;
28
29 ServiceWorkerManager::State::State() {}
30 ServiceWorkerManager::State::~State() {}
31
32 ServiceWorkerManager::ServiceWorkerManager(BrowserContext* context)
33 : context_(context), weak_this_factory_(this) {}
34 ServiceWorkerManager::~ServiceWorkerManager() {}
35
36 ServiceWorkerManager* ServiceWorkerManager::Get(
37 content::BrowserContext* context) {
38 return ServiceWorkerManagerFactory::GetForBrowserContext(context);
39 }
40
41 content::StoragePartition* ServiceWorkerManager::GetStoragePartition(
42 const ExtensionId& ext_id) const {
43 return content::BrowserContext::GetStoragePartitionForSite(
44 context_, Extension::GetBaseURLFromExtensionId(ext_id));
45 }
46
47 content::ServiceWorkerContext* ServiceWorkerManager::GetSWContext(
48 const ExtensionId& ext_id) const {
49 return GetStoragePartition(ext_id)->GetServiceWorkerContext();
50 }
51
52 // alecflett says that if we send a series of RegisterServiceWorker and
53 // UnregisterServiceWorker calls on the same scope to a
54 // ServiceWorkerContextCore, we're guaranteed that the callbacks come back in
55 // the same order, and that the last one will be the final state.
56 void ServiceWorkerManager::RegisterExtension(const Extension* extension) {
57 DCHECK_CURRENTLY_ON(BrowserThread::UI);
58 CHECK(BackgroundInfo::HasServiceWorker(extension));
59 State& ext_state = states_[extension->id()];
60 if (ext_state.registration == REGISTERING ||
61 ext_state.registration == REGISTERED)
62 return;
63 ext_state.registration = REGISTERING;
64 ++ext_state.outstanding_state_changes;
65 const GURL service_worker_script = extension->GetResourceURL(
66 BackgroundInfo::GetServiceWorkerScript(extension));
67 // TODO(jyasskin): Create the extension process in a cleaner way. We don't
68 // need a view, for instance. Using the service_worker_script as the
69 // background host is just totally horrible.
70 extensions::ProcessManager* process_manager =
71 ExtensionSystem::Get(context_)->process_manager();
72 CHECK(process_manager->CreateBackgroundHost(
73 extension,
74 service_worker_script,
75 base::Bind(&ServiceWorkerManager::ContinueRegistrationWithExtensionHost,
76 WeakThis(),
77 extension->id(),
78 extension->GetResourceURL("/*"),
79 service_worker_script)));
80 }
81
82 void ServiceWorkerManager::ContinueRegistrationWithExtensionHost(
83 const ExtensionId& extension_id,
84 const GURL& scope,
85 const GURL& service_worker_script) {
86 extensions::ProcessManager* process_manager =
87 ExtensionSystem::Get(context_)->process_manager();
88 ExtensionHost* host =
89 process_manager->GetBackgroundHostForExtension(extension_id);
90
91 GetSWContext(extension_id)->RegisterServiceWorker(
92 scope,
93 service_worker_script,
94 host->render_process_host()->GetID(),
95 base::Bind(
96 &ServiceWorkerManager::FinishRegistration, WeakThis(), extension_id));
97 }
98
99 void ServiceWorkerManager::FinishRegistration(const ExtensionId& extension_id,
100 bool success) {
101 DCHECK_CURRENTLY_ON(BrowserThread::UI);
102 State& ext_state = states_[extension_id];
103 --ext_state.outstanding_state_changes;
104 DCHECK_GE(ext_state.outstanding_state_changes, 0);
105 if (ext_state.outstanding_state_changes > 0)
106 return;
107
108 DCHECK_EQ(ext_state.registration, REGISTERING);
109 std::vector<Closure> to_run;
110 if (success) {
111 ext_state.registration = REGISTERED;
112 to_run.swap(ext_state.registration_succeeded);
113 ext_state.registration_failed.clear();
114 } else {
115 LOG(ERROR) << "Service Worker Registration failed for extension "
116 << extension_id;
117 to_run.swap(ext_state.registration_failed);
118 states_.erase(extension_id);
119 }
120
121 for (size_t i = 0; i < to_run.size(); ++i) {
122 to_run[i].Run();
123 }
124 }
125
126 void ServiceWorkerManager::UnregisterExtension(const Extension* extension) {
127 DCHECK_CURRENTLY_ON(BrowserThread::UI);
128 CHECK(BackgroundInfo::HasServiceWorker(extension));
129
130 base::hash_map<ExtensionId, State>::iterator it =
131 states_.find(extension->id());
132 if (it == states_.end()) {
133 // Extension isn't registered.
134 return;
135 }
136 State& ext_state = it->second;
137 if (ext_state.registration == UNREGISTERING)
138 return;
139
140 ext_state.registration = UNREGISTERING;
141 ++ext_state.outstanding_state_changes;
142
143 const GURL service_worker_script = extension->GetResourceURL(
144 BackgroundInfo::GetServiceWorkerScript(extension));
145 // TODO(jyasskin): Create the extension process in a cleaner way. We don't
146 // need a view, for instance. Using the service_worker_script as the
147 // background host is just totally horrible.
148 extensions::ProcessManager* process_manager =
149 ExtensionSystem::Get(context_)->process_manager();
150 CHECK(process_manager->CreateBackgroundHost(
151 extension,
152 service_worker_script,
153 base::Bind(&ServiceWorkerManager::ContinueUnregistrationWithExtensionHost,
154 WeakThis(),
155 extension->id(),
156 extension->GetResourceURL("/*"))));
157 }
158
159 void ServiceWorkerManager::ContinueUnregistrationWithExtensionHost(
160 const ExtensionId& extension_id,
161 const GURL& scope) {
162 extensions::ProcessManager* process_manager =
163 ExtensionSystem::Get(context_)->process_manager();
164 ExtensionHost* host =
165 process_manager->GetBackgroundHostForExtension(extension_id);
166
167 GetSWContext(extension_id)->UnregisterServiceWorker(
168 scope,
169 host->render_process_host()->GetID(),
170 base::Bind(&ServiceWorkerManager::FinishUnregistration,
171 WeakThis(),
172 extension_id));
173 }
174
175 void ServiceWorkerManager::FinishUnregistration(const ExtensionId& extension_id,
176 bool success) {
177 DCHECK_CURRENTLY_ON(BrowserThread::UI);
178 State& ext_state = states_[extension_id];
179 --ext_state.outstanding_state_changes;
180 DCHECK_GE(ext_state.outstanding_state_changes, 0);
181 if (ext_state.outstanding_state_changes > 0)
182 return;
183
184 DCHECK_EQ(ext_state.registration, UNREGISTERING);
185 std::vector<Closure> to_run;
186 if (success) {
187 to_run.swap(ext_state.unregistration_succeeded);
188 states_.erase(extension_id);
189 } else {
190 LOG(ERROR) << "Service Worker Unregistration failed for extension "
191 << extension_id;
192 ext_state.registration = REGISTERED;
193 to_run.swap(ext_state.unregistration_failed);
194 ext_state.unregistration_succeeded.clear();
195 }
196
197 for (size_t i = 0; i < to_run.size(); ++i) {
198 to_run[i].Run();
199 }
200 }
201
202 void ServiceWorkerManager::WhenRegistered(
203 const Extension* extension,
204 const tracked_objects::Location& from_here,
205 const base::Closure& success,
206 const base::Closure& failure) {
207 base::hash_map<ExtensionId, State>::iterator it =
208 states_.find(extension->id());
209 if (it == states_.end())
210 base::MessageLoop::current()->PostTask(from_here, failure);
211
212 State& state = it->second;
213 switch (state.registration) {
214 case UNREGISTERED:
215 case UNREGISTERING:
216 base::MessageLoop::current()->PostTask(from_here, failure);
217 break;
218 case REGISTERED:
219 base::MessageLoop::current()->PostTask(from_here, success);
220 break;
221 case REGISTERING:
222 state.registration_succeeded.push_back(success);
223 state.registration_failed.push_back(failure);
224 break;
225 }
226 }
227
228 void ServiceWorkerManager::WhenUnregistered(
229 const Extension* extension,
230 const tracked_objects::Location& from_here,
231 const base::Closure& success,
232 const base::Closure& failure) {
233 base::hash_map<ExtensionId, State>::iterator it =
234 states_.find(extension->id());
235 if (it == states_.end())
236 base::MessageLoop::current()->PostTask(from_here, success);
237
238 State& state = it->second;
239 switch(state.registration) {
240 case REGISTERED:
241 case REGISTERING:
242 base::MessageLoop::current()->PostTask(from_here, failure);
243 break;
244 case UNREGISTERED:
245 base::MessageLoop::current()->PostTask(from_here, success);
246 break;
247 case UNREGISTERING:
248 state.unregistration_succeeded.push_back(success);
249 state.unregistration_failed.push_back(failure);
250 break;
251 }
252 }
253
254 WeakPtr<ServiceWorkerManager> ServiceWorkerManager::WeakThis() {
255 return weak_this_factory_.GetWeakPtr();
256 }
257
258 // ServiceWorkerManagerFactory
259
260 ServiceWorkerManager* ServiceWorkerManagerFactory::GetForBrowserContext(
261 content::BrowserContext* context) {
262 return static_cast<ServiceWorkerManager*>(
263 GetInstance()->GetServiceForBrowserContext(context, true));
264 }
265
266 ServiceWorkerManagerFactory* ServiceWorkerManagerFactory::GetInstance() {
267 return Singleton<ServiceWorkerManagerFactory>::get();
268 }
269
270 void ServiceWorkerManagerFactory::SetInstanceForTesting(
271 content::BrowserContext* context,
272 ServiceWorkerManager* manager) {
273 Associate(context, manager);
274 }
275
276 ServiceWorkerManagerFactory::ServiceWorkerManagerFactory()
277 : BrowserContextKeyedServiceFactory(
278 "ServiceWorkerManager",
279 BrowserContextDependencyManager::GetInstance()) {}
280
281 ServiceWorkerManagerFactory::~ServiceWorkerManagerFactory() {}
282
283 KeyedService* ServiceWorkerManagerFactory::BuildServiceInstanceFor(
284 content::BrowserContext* context) const {
285 return new ServiceWorkerManager(context);
286 }
287
288 // TODO(jyasskin): Deal with incognito mode.
289 content::BrowserContext* ServiceWorkerManagerFactory::GetBrowserContextToUse(
290 content::BrowserContext* context) const {
291 return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
292 }
293
294 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698