1 // Copyright 2013 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_context_wrapper.h" 6 7 #include <map> 8 9 #include "base/files/file_path.h" 10 #include "base/logging.h" 11 #include "base/threading/sequenced_worker_pool.h" 12 #include "content/browser/fileapi/chrome_blob_storage_context.h" 13 #include "content/browser/service_worker/service_worker_context_core.h" 14 #include "content/browser/service_worker/service_worker_context_observer.h" 15 #include "content/browser/service_worker/service_worker_process_manager.h" 16 #include "content/public/browser/browser_context.h" 17 #include "content/public/browser/browser_thread.h" 18 #include "net/url_request/url_request_context_getter.h" 19 #include "storage/browser/blob/blob_storage_context.h" 20 #include "storage/browser/quota/quota_manager_proxy.h" 21 22 namespace content { 23 24 ServiceWorkerContextWrapper::ServiceWorkerContextWrapper( 25 BrowserContext* browser_context) 26 : observer_list_( 27 new ObserverListThreadSafe<ServiceWorkerContextObserver>()), 28 process_manager_(new ServiceWorkerProcessManager(browser_context)), 29 is_incognito_(false) { 30 } 31 32 ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() { 33 } 34 35 void ServiceWorkerContextWrapper::Init( 36 const base::FilePath& user_data_directory, 37 storage::QuotaManagerProxy* quota_manager_proxy) { 38 is_incognito_ = user_data_directory.empty(); 39 scoped_refptr<base::SequencedTaskRunner> database_task_runner = 40 BrowserThread::GetBlockingPool()-> 41 GetSequencedTaskRunnerWithShutdownBehavior( 42 BrowserThread::GetBlockingPool()->GetSequenceToken(), 43 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); 44 scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread = 45 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE); 46 scoped_refptr<base::SequencedTaskRunner> cache_task_runner = 47 BrowserThread::GetBlockingPool() 48 ->GetSequencedTaskRunnerWithShutdownBehavior( 49 BrowserThread::GetBlockingPool()->GetSequenceToken(), 50 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); 51 InitInternal(user_data_directory, 52 cache_task_runner, 53 database_task_runner, 54 disk_cache_thread, 55 quota_manager_proxy); 56 } 57 58 void ServiceWorkerContextWrapper::Shutdown() { 59 DCHECK_CURRENTLY_ON(BrowserThread::UI); 60 process_manager_->Shutdown(); 61 BrowserThread::PostTask( 62 BrowserThread::IO, 63 FROM_HERE, 64 base::Bind(&ServiceWorkerContextWrapper::ShutdownOnIO, this)); 65 } 66 67 void ServiceWorkerContextWrapper::DeleteAndStartOver() { 68 DCHECK_CURRENTLY_ON(BrowserThread::IO); 69 context_core_->DeleteAndStartOver( 70 base::Bind(&ServiceWorkerContextWrapper::DidDeleteAndStartOver, this)); 71 } 72 73 ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() { 74 DCHECK_CURRENTLY_ON(BrowserThread::IO); 75 return context_core_.get(); 76 } 77 78 static void FinishRegistrationOnIO( 79 const ServiceWorkerContext::ResultCallback& continuation, 80 ServiceWorkerStatusCode status, 81 int64 registration_id, 82 int64 version_id) { 83 DCHECK_CURRENTLY_ON(BrowserThread::IO); 84 BrowserThread::PostTask( 85 BrowserThread::UI, 86 FROM_HERE, 87 base::Bind(continuation, status == SERVICE_WORKER_OK)); 88 } 89 90 void ServiceWorkerContextWrapper::RegisterServiceWorker( 91 const GURL& pattern, 92 const GURL& script_url, 93 const ResultCallback& continuation) { 94 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 95 BrowserThread::PostTask( 96 BrowserThread::IO, 97 FROM_HERE, 98 base::Bind(&ServiceWorkerContextWrapper::RegisterServiceWorker, 99 this, 100 pattern, 101 script_url, 102 continuation)); 103 return; 104 } 105 106 context()->RegisterServiceWorker( 107 pattern, 108 script_url, 109 NULL /* provider_host */, 110 base::Bind(&FinishRegistrationOnIO, continuation)); 111 } 112 113 static void FinishUnregistrationOnIO( 114 const ServiceWorkerContext::ResultCallback& continuation, 115 ServiceWorkerStatusCode status) { 116 DCHECK_CURRENTLY_ON(BrowserThread::IO); 117 BrowserThread::PostTask( 118 BrowserThread::UI, 119 FROM_HERE, 120 base::Bind(continuation, status == SERVICE_WORKER_OK)); 121 } 122 123 void ServiceWorkerContextWrapper::UnregisterServiceWorker( 124 const GURL& pattern, 125 const ResultCallback& continuation) { 126 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 127 BrowserThread::PostTask( 128 BrowserThread::IO, 129 FROM_HERE, 130 base::Bind(&ServiceWorkerContextWrapper::UnregisterServiceWorker, 131 this, 132 pattern, 133 continuation)); 134 return; 135 } 136 137 context()->UnregisterServiceWorker( 138 pattern, 139 base::Bind(&FinishUnregistrationOnIO, continuation)); 140 } 141 142 void ServiceWorkerContextWrapper::Terminate() { 143 DCHECK_CURRENTLY_ON(BrowserThread::UI); 144 process_manager_->Shutdown(); 145 } 146 147 void ServiceWorkerContextWrapper::GetAllOriginsInfo( 148 const GetUsageInfoCallback& callback) { 149 DCHECK_CURRENTLY_ON(BrowserThread::IO); 150 context_core_->storage()->GetAllRegistrations(base::Bind( 151 &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins, 152 this, 153 callback)); 154 } 155 156 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins( 157 const GetUsageInfoCallback& callback, 158 const std::vector<ServiceWorkerRegistrationInfo>& registrations) { 159 DCHECK_CURRENTLY_ON(BrowserThread::IO); 160 std::vector<ServiceWorkerUsageInfo> usage_infos; 161 162 std::map<GURL, ServiceWorkerUsageInfo> origins; 163 for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it = 164 registrations.begin(); 165 it != registrations.end(); 166 ++it) { 167 const ServiceWorkerRegistrationInfo& registration_info = *it; 168 GURL origin = registration_info.pattern.GetOrigin(); 169 170 ServiceWorkerUsageInfo& usage_info = origins[origin]; 171 if (usage_info.origin.is_empty()) 172 usage_info.origin = origin; 173 usage_info.scopes.push_back(registration_info.pattern); 174 } 175 176 for (std::map<GURL, ServiceWorkerUsageInfo>::const_iterator it = 177 origins.begin(); 178 it != origins.end(); 179 ++it) { 180 usage_infos.push_back(it->second); 181 } 182 183 callback.Run(usage_infos); 184 } 185 186 namespace { 187 188 void EmptySuccessCallback(bool success) { 189 } 190 191 } // namespace 192 193 void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin_url) { 194 DCHECK_CURRENTLY_ON(BrowserThread::IO); 195 context_core_->storage()->GetAllRegistrations(base::Bind( 196 &ServiceWorkerContextWrapper::DidGetAllRegistrationsForDeleteForOrigin, 197 this, 198 origin_url)); 199 } 200 201 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForDeleteForOrigin( 202 const GURL& origin, 203 const std::vector<ServiceWorkerRegistrationInfo>& registrations) { 204 DCHECK_CURRENTLY_ON(BrowserThread::IO); 205 206 for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it = 207 registrations.begin(); 208 it != registrations.end(); 209 ++it) { 210 const ServiceWorkerRegistrationInfo& registration_info = *it; 211 if (origin == registration_info.pattern.GetOrigin()) { 212 UnregisterServiceWorker(registration_info.pattern, 213 base::Bind(&EmptySuccessCallback)); 214 } 215 } 216 } 217 218 void ServiceWorkerContextWrapper::AddObserver( 219 ServiceWorkerContextObserver* observer) { 220 observer_list_->AddObserver(observer); 221 } 222 223 void ServiceWorkerContextWrapper::RemoveObserver( 224 ServiceWorkerContextObserver* observer) { 225 observer_list_->RemoveObserver(observer); 226 } 227 228 void ServiceWorkerContextWrapper::SetBlobParametersForCache( 229 net::URLRequestContextGetter* request_context, 230 ChromeBlobStorageContext* blob_storage_context) { 231 DCHECK_CURRENTLY_ON(BrowserThread::IO); 232 233 if (context_core_ && request_context && blob_storage_context) { 234 context_core_->SetBlobParametersForCache( 235 request_context->GetURLRequestContext(), 236 blob_storage_context->context()->AsWeakPtr()); 237 } 238 } 239 240 void ServiceWorkerContextWrapper::InitInternal( 241 const base::FilePath& user_data_directory, 242 const scoped_refptr<base::SequencedTaskRunner>& stores_task_runner, 243 const scoped_refptr<base::SequencedTaskRunner>& database_task_runner, 244 const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread, 245 storage::QuotaManagerProxy* quota_manager_proxy) { 246 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 247 BrowserThread::PostTask( 248 BrowserThread::IO, 249 FROM_HERE, 250 base::Bind(&ServiceWorkerContextWrapper::InitInternal, 251 this, 252 user_data_directory, 253 stores_task_runner, 254 database_task_runner, 255 disk_cache_thread, 256 make_scoped_refptr(quota_manager_proxy))); 257 return; 258 } 259 DCHECK(!context_core_); 260 context_core_.reset(new ServiceWorkerContextCore(user_data_directory, 261 stores_task_runner, 262 database_task_runner, 263 disk_cache_thread, 264 quota_manager_proxy, 265 observer_list_.get(), 266 this)); 267 } 268 269 void ServiceWorkerContextWrapper::ShutdownOnIO() { 270 DCHECK_CURRENTLY_ON(BrowserThread::IO); 271 context_core_.reset(); 272 } 273 274 void ServiceWorkerContextWrapper::DidDeleteAndStartOver( 275 ServiceWorkerStatusCode status) { 276 DCHECK_CURRENTLY_ON(BrowserThread::IO); 277 if (status != SERVICE_WORKER_OK) { 278 context_core_.reset(); 279 return; 280 } 281 context_core_.reset(new ServiceWorkerContextCore(context_core_.get(), this)); 282 DVLOG(1) << "Restarted ServiceWorkerContextCore successfully."; 283 } 284 285 } // namespace content 286