OLD | NEW |
---|---|
(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 | |
OLD | NEW |