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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: extensions/browser/service_worker_manager.cc
diff --git a/extensions/browser/service_worker_manager.cc b/extensions/browser/service_worker_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f6e5ff71fbb17a829bbfdb457cb01a011fd6abdf
--- /dev/null
+++ b/extensions/browser/service_worker_manager.cc
@@ -0,0 +1,289 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/service_worker_manager.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/common/manifest_handlers/background_info.h"
+
+namespace extensions {
+
+using base::Callback;
+using base::Closure;
+using base::WeakPtr;
+using content::BrowserContext;
+using content::BrowserThread;
+using content::ServiceWorkerStatusCode;
+
+static const char* CurrentBrowserThreadName() {
+ BrowserThread::ID id;
+ if (BrowserThread::GetCurrentThreadIdentifier(&id)) {
+ switch (id) {
+ case BrowserThread::UI:
+ return "UI";
+ case BrowserThread::DB:
+ return "DB";
+ case BrowserThread::FILE:
+ return "FILE";
+ case BrowserThread::FILE_USER_BLOCKING:
+ return "FILE_USER_BLOCKING";
+ case BrowserThread::PROCESS_LAUNCHER:
+ return "PROCESS_LAUNCHER";
+ case BrowserThread::CACHE:
+ return "CACHE";
+ case BrowserThread::IO:
+ return "IO";
+ default:
+ break;
+ }
+ }
+ return "Unknown";
+}
+
+static void DCheckCurrentlyOn(BrowserThread::ID thread) {
+ DCHECK(BrowserThread::CurrentlyOn(thread)) << CurrentBrowserThreadName();
scheib 2014/03/10 21:31:38 Maybe base::MessageLoop::current()->thread_name();
+}
+
+ServiceWorkerManager::State::State() {}
+ServiceWorkerManager::State::~State() {}
+
+ServiceWorkerManager::ServiceWorkerManager(BrowserContext* context)
+ : context_(context), weak_this_factory_(this) {}
+ServiceWorkerManager::~ServiceWorkerManager() {}
+
+ServiceWorkerManager* ServiceWorkerManager::Get(
+ content::BrowserContext* context) {
+ return ServiceWorkerManagerFactory::GetForBrowserContext(context);
+}
+
+content::StoragePartition* ServiceWorkerManager::GetStoragePartition(
+ const Extension* ext) const {
+ return content::BrowserContext::GetStoragePartitionForSite(
+ context_, Extension::GetBaseURLFromExtensionId(ext->id()));
+}
+
+scoped_refptr<content::ServiceWorkerContextWrapper>
+ServiceWorkerManager::GetSWContext(const Extension* ext) const {
+ return GetStoragePartition(ext)->GetServiceWorkerContext();
+}
+
+template <typename Arg1>
+static void RunCallback1(const Callback<void(Arg1)>& callback,
+ const Arg1& arg1) {
+ callback.Run(arg1);
+}
+
+static void FinishRegister(
+ const Callback<void(ServiceWorkerStatusCode)>& continuation,
+ content::ServiceWorkerStatusCode status,
+ int64 registration_id) {
+ DCheckCurrentlyOn(BrowserThread::IO);
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&RunCallback1<ServiceWorkerStatusCode>, continuation, status));
kinuko 2014/03/10 07:03:19 nit: why don't we just do base::Bind(continuation,
+}
+
+static void DoRegister(
+ const scoped_refptr<content::ServiceWorkerContextWrapper>&
+ service_worker_context,
+ const ExtensionId& extension_id,
+ const GURL& service_worker_script,
+ const Callback<void(ServiceWorkerStatusCode)>& continuation) {
+ DCheckCurrentlyOn(BrowserThread::IO);
+ service_worker_context->context()->RegisterServiceWorker(
+ Extension::GetBaseURLFromExtensionId(extension_id).Resolve("/*"),
+ service_worker_script,
+ -1,
+ base::Bind(&FinishRegister, continuation));
+}
+
+// alecflett says that if we send a series of RegisterServiceWorker and
+// UnregisterServiceWorker calls to a ServiceWorkerContextCore, we're guaranteed
+// 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
+// the final state.
+void ServiceWorkerManager::RegisterExtension(const Extension* extension) {
+ DCheckCurrentlyOn(BrowserThread::UI);
+ CHECK(BackgroundInfo::HasServiceWorker(extension));
+ State& ext_state = states_[extension->id()];
+ if (ext_state.registration == REGISTERING ||
+ ext_state.registration == REGISTERED)
+ return;
+ ext_state.registration = REGISTERING;
+ ++ext_state.outstanding_state_changes;
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&DoRegister,
+ GetSWContext(extension),
+ extension->id(),
+ extension->GetResourceURL(
+ BackgroundInfo::GetServiceWorkerScript(extension)),
+ base::Bind(&ServiceWorkerManager::FinishRegistration,
+ WeakThis(),
+ extension->id())));
+}
+
+void ServiceWorkerManager::FinishRegistration(const ExtensionId& extension_id,
+ ServiceWorkerStatusCode result) {
+ DCheckCurrentlyOn(BrowserThread::UI);
+ State& ext_state = states_[extension_id];
+ --ext_state.outstanding_state_changes;
+ DCHECK_GE(ext_state.outstanding_state_changes, 0);
+ if (ext_state.outstanding_state_changes > 0)
+ return;
+
+ DCHECK_EQ(ext_state.registration, REGISTERING);
+ std::vector<Closure> to_run;
+ switch (result) {
+ case content::SERVICE_WORKER_OK:
+ ext_state.registration = REGISTERED;
+ to_run.swap(ext_state.registration_succeeded);
+ ext_state.registration_failed.clear();
+ break;
+ default:
+ LOG(ERROR) << "Service Worker Registration failed for extension "
+ << extension_id << ": "
+ << content::ServiceWorkerStatusToString(result);
+ to_run.swap(ext_state.registration_failed);
+ states_.erase(extension_id);
+ break;
+ }
+
+ for (size_t i = 0; i < to_run.size(); ++i) {
+ to_run[i].Run();
+ }
+}
+
+static void FinishUnregister(
+ const Callback<void(ServiceWorkerStatusCode)>& continuation,
+ content::ServiceWorkerStatusCode status) {
+ DCheckCurrentlyOn(BrowserThread::IO);
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&RunCallback1<ServiceWorkerStatusCode>, continuation, status));
+}
+
+static void DoUnregister(
+ const scoped_refptr<content::ServiceWorkerContextWrapper>&
+ service_worker_context,
+ const ExtensionId& extension_id,
+ const Callback<void(ServiceWorkerStatusCode)>& continuation) {
+ DCheckCurrentlyOn(BrowserThread::IO);
+ service_worker_context->context()->UnregisterServiceWorker(
+ Extension::GetBaseURLFromExtensionId(extension_id).Resolve("/*"),
+ -1,
+ base::Bind(&FinishUnregister, continuation));
+}
+
+void ServiceWorkerManager::UnregisterExtension(const Extension* extension) {
+ DCheckCurrentlyOn(BrowserThread::UI);
+ CHECK(BackgroundInfo::HasServiceWorker(extension));
+
+ base::hash_map<ExtensionId, State>::iterator it =
+ states_.find(extension->id());
+ if (it == states_.end()) {
+ // Extension isn't registered.
+ return;
+ }
+ State& ext_state = it->second;
+ if (ext_state.registration == UNREGISTERING)
+ return;
+
+ ext_state.registration = UNREGISTERING;
+ ++ext_state.outstanding_state_changes;
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&DoUnregister,
+ GetSWContext(extension),
+ extension->id(),
+ base::Bind(&ServiceWorkerManager::FinishUnregistration,
+ WeakThis(),
+ extension->id())));
+}
+
+void ServiceWorkerManager::FinishUnregistration(
+ const ExtensionId& extension_id,
+ ServiceWorkerStatusCode result) {
+ DCheckCurrentlyOn(BrowserThread::UI);
+ State& ext_state = states_[extension_id];
+ --ext_state.outstanding_state_changes;
+ DCHECK_GE(ext_state.outstanding_state_changes, 0);
+ if (ext_state.outstanding_state_changes > 0)
+ return;
+
+ DCHECK_EQ(ext_state.registration, UNREGISTERING);
+ std::vector<Closure> to_run;
+ switch (result) {
+ case content::SERVICE_WORKER_OK:
+ to_run.swap(ext_state.unregistration_succeeded);
+ states_.erase(extension_id);
+ break;
+ default:
+ LOG(ERROR) << "Service Worker Unregistration failed for extension "
+ << extension_id << ": "
+ << content::ServiceWorkerStatusToString(result);
+ ext_state.registration = REGISTERED;
+ to_run.swap(ext_state.unregistration_failed);
+ ext_state.unregistration_succeeded.clear();
+ break;
+ }
+
+ for (size_t i = 0; i < to_run.size(); ++i) {
+ to_run[i].Run();
+ }
+}
+
+WeakPtr<ServiceWorkerManager> ServiceWorkerManager::WeakThis() {
+ return weak_this_factory_.GetWeakPtr();
+}
+
+// ServiceWorkerManagerFactory
+
+ServiceWorkerManager* ServiceWorkerManagerFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<ServiceWorkerManager*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+ServiceWorkerManagerFactory* ServiceWorkerManagerFactory::GetInstance() {
+ return Singleton<ServiceWorkerManagerFactory>::get();
+}
+
+void ServiceWorkerManagerFactory::SetInstanceForTesting(
+ content::BrowserContext* context,
+ ServiceWorkerManager* manager) {
+ Associate(context, manager);
+}
+
+ServiceWorkerManagerFactory::ServiceWorkerManagerFactory()
+ : BrowserContextKeyedServiceFactory(
+ "ServiceWorkerManager",
+ BrowserContextDependencyManager::GetInstance()) {}
+
+ServiceWorkerManagerFactory::~ServiceWorkerManagerFactory() {}
+
+BrowserContextKeyedService*
+ServiceWorkerManagerFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new ServiceWorkerManager(context);
+}
+
+// TODO(jyasskin): Deal with incognito mode.
+content::BrowserContext* ServiceWorkerManagerFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
+}
+
+} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698