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

Unified Diff: content/browser/service_worker/service_worker_internals_ui.cc

Issue 182383008: Create chrome://serviceworker-internals (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix GetInfo / const stuff Created 6 years, 10 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: content/browser/service_worker/service_worker_internals_ui.cc
diff --git a/content/browser/service_worker/service_worker_internals_ui.cc b/content/browser/service_worker/service_worker_internals_ui.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e34a7f1e3dd8999d2bd5212a4dd5233335a87591
--- /dev/null
+++ b/content/browser/service_worker/service_worker_internals_ui.cc
@@ -0,0 +1,401 @@
+// Copyright (c) 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 "content/browser/service_worker/service_worker_internals_ui.h"
+
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/values.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_version.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/common/url_constants.h"
+#include "grit/content_resources.h"
+
+using base::DictionaryValue;
+using base::FundamentalValue;
+using base::ListValue;
+using base::StringValue;
+using base::Value;
+using base::WeakPtr;
+
+namespace content {
+
+// This class, and the parameters to the *IOTHread methods should be
+// created on the UI thread, where it will delete itself and
+// those values.
michaeln 2014/03/06 01:19:02 comment seems stale
alecflett 2014/03/06 19:25:15 nope.. the operation eventually proxies itself bac
michaeln 2014/03/06 19:54:15 But it doesn't "delete itself" and see other comme
+class ServiceWorkerInternalsUI::OperationProxy
+ : public base::RefCountedThreadSafe<
+ ServiceWorkerInternalsUI::OperationProxy> {
+ public:
+ OperationProxy(const WeakPtr<ServiceWorkerInternalsUI> internals,
+ scoped_ptr<ListValue> original_args)
+ : internals_(internals), original_args_(original_args.Pass()) {}
+
+ void GetRegistrationsOnIOThread(ServiceWorkerContextWrapper* context,
+ const base::FilePath& context_path);
+ void UnregisterOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,
+ const GURL& scope);
+ void StartWorkerOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,
+ const GURL& scope);
+ void StopWorkerOnIOThread(scoped_refptr<ServiceWorkerContextWrapper> context,
+ const GURL& scope);
+
+ private:
+ friend class base::RefCountedThreadSafe<
+ ServiceWorkerInternalsUI::OperationProxy>;
+ ~OperationProxy() {}
+ void OnHaveRegistrations(
+ const base::FilePath& context_path,
+ const std::vector<ServiceWorkerRegistrationInfo>& registrations);
+
+ void OperationComplete(ServiceWorkerStatusCode status);
+
+ void StartActiveWorker(
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration);
+
+ void StopActiveWorker(
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration);
+
+ WeakPtr<ServiceWorkerInternalsUI> internals_;
+ scoped_ptr<ListValue> original_args_;
michaeln 2014/03/06 01:19:02 I'm not so familiar with ListValue, does it matter
alecflett 2014/03/06 19:25:15 They're deleted on the UI thread, where they're cr
michaeln 2014/03/06 19:54:15 Thats typically what will happen given how its use
+};
+
+ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui)
+ : WebUIController(web_ui) {
+ WebUIDataSource* source =
+ WebUIDataSource::Create(kChromeUIServiceWorkerInternalsHost);
+ source->SetUseJsonJSFormatV2();
+ source->SetJsonPath("strings.js");
+ source->AddResourcePath("serviceworker_internals.js",
+ IDR_SERVICE_WORKER_INTERNALS_JS);
+ source->AddResourcePath("serviceworker_internals.css",
+ IDR_SERVICE_WORKER_INTERNALS_CSS);
+ source->SetDefaultResource(IDR_SERVICE_WORKER_INTERNALS_HTML);
+
+ BrowserContext* browser_context =
+ web_ui->GetWebContents()->GetBrowserContext();
+ WebUIDataSource::Add(browser_context, source);
+
+ web_ui->RegisterMessageCallback(
+ "getAllRegistrations",
+ base::Bind(&ServiceWorkerInternalsUI::GetAllRegistrations,
+ base::Unretained(this)));
+ web_ui->RegisterMessageCallback(
+ "start",
+ base::Bind(&ServiceWorkerInternalsUI::StartWorker,
+ base::Unretained(this)));
+ web_ui->RegisterMessageCallback(
+ "stop",
+ base::Bind(&ServiceWorkerInternalsUI::StopWorker,
+ base::Unretained(this)));
+ web_ui->RegisterMessageCallback(
+ "unregister",
+ base::Bind(&ServiceWorkerInternalsUI::Unregister,
+ base::Unretained(this)));
+}
+
+ServiceWorkerInternalsUI::~ServiceWorkerInternalsUI() {}
+
+void ServiceWorkerInternalsUI::GetAllRegistrations(const ListValue* args) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ BrowserContext* browser_context =
+ web_ui()->GetWebContents()->GetBrowserContext();
+
+ // Safe to use base::Unretained(this) because
+ // ForEachStoragePartition is synchronous.
+ BrowserContext::StoragePartitionCallback cb =
+ base::Bind(&ServiceWorkerInternalsUI::AddContextFromStoragePartition,
+ base::Unretained(this));
+ BrowserContext::ForEachStoragePartition(browser_context, cb);
+}
+
+void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
+ StoragePartition* partition) {
+ scoped_refptr<ServiceWorkerContextWrapper> context =
+ partition->GetServiceWorkerContext();
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread,
+ new OperationProxy(AsWeakPtr(), scoped_ptr<ListValue>()),
+ context,
+ partition->GetPath()));
+}
+
+namespace {
+void FindContext(const base::FilePath& partition_path,
+ StoragePartition** result_partition,
+ scoped_refptr<ServiceWorkerContextWrapper>* result_context,
+ StoragePartition* storage_partition) {
+ if (storage_partition->GetPath() == partition_path) {
+ *result_partition = storage_partition;
+ *result_context = storage_partition->GetServiceWorkerContext();
+ }
+}
+} // namespace
+
+bool ServiceWorkerInternalsUI::GetRegistrationInfo(
+ const ListValue* args,
+ base::FilePath* partition_path,
+ GURL* scope,
+ scoped_refptr<ServiceWorkerContextWrapper>* context) const {
+ base::FilePath::StringType path_string;
+ if (!args->GetString(0, &path_string))
+ return false;
+ *partition_path = base::FilePath(path_string);
+
+ std::string scope_string;
+ if (!args->GetString(1, &scope_string))
+ return false;
+ *scope = GURL(scope_string);
+
+ BrowserContext* browser_context =
+ web_ui()->GetWebContents()->GetBrowserContext();
+
+ StoragePartition* result_partition(NULL);
+ BrowserContext::StoragePartitionCallback cb =
+ base::Bind(&FindContext, *partition_path, &result_partition, context);
+ BrowserContext::ForEachStoragePartition(browser_context, cb);
+
+ if (!result_partition || !(*context))
+ return false;
+
+ return true;
+}
+
+void ServiceWorkerInternalsUI::Unregister(const ListValue* args) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ base::FilePath partition_path;
+ GURL scope;
+ scoped_refptr<ServiceWorkerContextWrapper> context;
+ if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
+ return;
+
+ scoped_ptr<ListValue> args_copy(args->DeepCopy());
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread,
+ new OperationProxy(AsWeakPtr(), args_copy.Pass()),
+ context,
+ scope));
+}
+
+void ServiceWorkerInternalsUI::StartWorker(const ListValue* args) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ base::FilePath partition_path;
+ GURL scope;
+ scoped_refptr<ServiceWorkerContextWrapper> context;
+ if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
+ return;
+
+ scoped_ptr<ListValue> args_copy(args->DeepCopy());
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread,
+ new OperationProxy(AsWeakPtr(), args_copy.Pass()),
+ context,
+ scope));
+}
+
+void ServiceWorkerInternalsUI::StopWorker(const ListValue* args) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ base::FilePath partition_path;
+ GURL scope;
+ scoped_refptr<ServiceWorkerContextWrapper> context;
+ if (!GetRegistrationInfo(args, &partition_path, &scope, &context))
+ return;
+
+ scoped_ptr<ListValue> args_copy(args->DeepCopy());
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread,
+ new OperationProxy(AsWeakPtr(), args_copy.Pass()),
+ context,
+ scope));
+}
+
+void ServiceWorkerInternalsUI::OperationProxy::GetRegistrationsOnIOThread(
+ ServiceWorkerContextWrapper* context,
+ const base::FilePath& context_path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ context->context()->storage()->GetAllRegistrations(
+ base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
+ this,
+ context_path));
+}
+
+void ServiceWorkerInternalsUI::OperationProxy::UnregisterOnIOThread(
+ scoped_refptr<ServiceWorkerContextWrapper> context,
+ const GURL& scope) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ context->context()->UnregisterServiceWorker(
+ scope,
+ 0, // render process id?
+ base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
+ this));
+}
+
+void ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread(
+ scoped_refptr<ServiceWorkerContextWrapper> context,
+ const GURL& scope) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // TODO(alecflett): Add support for starting/stopping workers for
+ // pending versions too.
+ context->context()->storage()->FindRegistrationForPattern(
+ scope,
+ base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StartActiveWorker,
+ this));
+}
+
+void ServiceWorkerInternalsUI::OperationProxy::StopWorkerOnIOThread(
+ scoped_refptr<ServiceWorkerContextWrapper> context,
+ const GURL& scope) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // TODO(alecflett): Add support for starting/stopping workers for
+ // pending versions too.
+ context->context()->storage()->FindRegistrationForPattern(
+ scope,
+ base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker,
+ this));
+}
+
+namespace {
+void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
+ DictionaryValue* info) {
+ switch (version.status) {
+ case ServiceWorkerVersion::STOPPED:
+ info->SetString("status", "STOPPED");
+ break;
+ case EmbeddedWorkerInstance::STARTING:
+ info->SetString("status", "STARTING");
+ break;
+ case EmbeddedWorkerInstance::RUNNING:
+ info->SetString("status", "RUNNING");
+ break;
+ case EmbeddedWorkerInstance::STOPPING:
+ info->SetString("status", "STOPPING");
+ break;
+ }
+
+ info->SetInteger("process_id", version.process_id);
+ // is this hardware thread or internal thread?
+ info->SetInteger("thread_id", version.thread_id);
+}
+} // namespace
+
+void ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations(
+ const base::FilePath& context_path,
+ const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
michaeln 2014/03/06 19:54:15 fyi: OnHaveRegistrations may have been run on the
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
+ this,
+ context_path,
+ registrations));
+ return;
+ }
+
+ ListValue result;
+ for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it =
+ registrations.begin();
+ it != registrations.end();
+ ++it) {
+ const ServiceWorkerRegistrationInfo& registration = *it;
+ DictionaryValue* registration_info = new DictionaryValue();
+ registration_info->SetString("scope", registration.pattern.spec());
+ registration_info->SetString("script_url", registration.script_url.spec());
+
+ if (!registration.active_version.is_null) {
+ DictionaryValue* active_info = new DictionaryValue();
+ UpdateVersionInfo(registration.active_version, active_info);
+ registration_info->Set("active", active_info);
+ }
+
+ if (!registration.pending_version.is_null) {
+ DictionaryValue* pending_info = new DictionaryValue();
+ UpdateVersionInfo(registration.active_version, pending_info);
+ registration_info->Set("pending", pending_info);
+ }
+
+ result.Append(registration_info);
+ }
+
+ if (internals_)
+ internals_->web_ui()->CallJavascriptFunction(
+ "serviceworker.onPartitionData",
+ result,
+ StringValue(context_path.value()));
+}
+
+void ServiceWorkerInternalsUI::OperationProxy::OperationComplete(
+ ServiceWorkerStatusCode status) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
+ this,
+ status));
+ return;
+ }
+
+ original_args_->Insert(0, new FundamentalValue(static_cast<int>(status)));
+ if (internals_)
+ internals_->web_ui()->CallJavascriptFunction(
+ "serviceworker.onOperationComplete",
+ std::vector<const Value*>(original_args_->begin(),
+ original_args_->end()));
+}
+
+void ServiceWorkerInternalsUI::OperationProxy::StartActiveWorker(
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (status == SERVICE_WORKER_OK) {
+ registration->active_version()->StartWorker(base::Bind(
+ &ServiceWorkerInternalsUI::OperationProxy::OperationComplete, this));
+ return;
+ }
+
+ OperationComplete(status);
+}
+
+void ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker(
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (status == SERVICE_WORKER_OK) {
+ registration->active_version()->StopWorker(base::Bind(
+ &ServiceWorkerInternalsUI::OperationProxy::OperationComplete, this));
+ return;
+ }
+
+ OperationComplete(status);
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698