This source file includes following definitions.
- original_args_
- GetAllRegistrations
- AddContextFromStoragePartition
- FindContext
- GetRegistrationInfo
- DispatchSyncEventToWorker
- Unregister
- StartWorker
- StopWorker
- GetRegistrationsOnIOThread
- UnregisterOnIOThread
- StartWorkerOnIOThread
- StopWorkerOnIOThread
- DispatchSyncEventToWorkerOnIOThread
- UpdateVersionInfo
- OnHaveRegistrations
- OperationComplete
- StartActiveWorker
- StopActiveWorker
- DispatchSyncEventToActiveWorker
#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 {
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);
void DispatchSyncEventToWorkerOnIOThread(
scoped_refptr<ServiceWorkerContextWrapper> context,
const GURL& scope);
private:
friend class base::RefCountedThreadSafe<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);
void DispatchSyncEventToActiveWorker(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
WeakPtr<ServiceWorkerInternalsUI> internals_;
scoped_ptr<ListValue> original_args_;
};
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)));
web_ui->RegisterMessageCallback(
"sync",
base::Bind(&ServiceWorkerInternalsUI::DispatchSyncEventToWorker,
base::Unretained(this)));
}
ServiceWorkerInternalsUI::~ServiceWorkerInternalsUI() {}
void ServiceWorkerInternalsUI::GetAllRegistrations(const ListValue* args) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
BrowserContext* browser_context =
web_ui()->GetWebContents()->GetBrowserContext();
BrowserContext::StoragePartitionCallback cb =
base::Bind(&ServiceWorkerInternalsUI::AddContextFromStoragePartition,
base::Unretained(this));
BrowserContext::ForEachStoragePartition(browser_context, cb);
}
void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
StoragePartition* partition) {
scoped_refptr<ServiceWorkerContextWrapper> context =
static_cast<ServiceWorkerContextWrapper*>(
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 = static_cast<ServiceWorkerContextWrapper*>(
storage_partition->GetServiceWorkerContext());
}
}
}
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::DispatchSyncEventToWorker(
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::
DispatchSyncEventToWorkerOnIOThread,
new OperationProxy(AsWeakPtr(), args_copy.Pass()),
context,
scope));
}
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,
base::Bind(&ServiceWorkerInternalsUI::OperationProxy::OperationComplete,
this));
}
void ServiceWorkerInternalsUI::OperationProxy::StartWorkerOnIOThread(
scoped_refptr<ServiceWorkerContextWrapper> context,
const GURL& scope) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
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));
context->context()->storage()->FindRegistrationForPattern(
scope,
base::Bind(&ServiceWorkerInternalsUI::OperationProxy::StopActiveWorker,
this));
}
void
ServiceWorkerInternalsUI::OperationProxy::DispatchSyncEventToWorkerOnIOThread(
scoped_refptr<ServiceWorkerContextWrapper> context,
const GURL& scope) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
context->context()->storage()->FindRegistrationForPattern(
scope,
base::Bind(&ServiceWorkerInternalsUI::OperationProxy::
DispatchSyncEventToActiveWorker,
this));
}
namespace {
void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
DictionaryValue* info) {
switch (version.running_status) {
case ServiceWorkerVersion::STOPPED:
info->SetString("running_status", "STOPPED");
break;
case ServiceWorkerVersion::STARTING:
info->SetString("running_status", "STARTING");
break;
case ServiceWorkerVersion::RUNNING:
info->SetString("running_status", "RUNNING");
break;
case ServiceWorkerVersion::STOPPING:
info->SetString("running_status", "STOPPING");
break;
}
switch (version.status) {
case ServiceWorkerVersion::NEW:
info->SetString("status", "NEW");
break;
case ServiceWorkerVersion::INSTALLING:
info->SetString("status", "INSTALLING");
break;
case ServiceWorkerVersion::INSTALLED:
info->SetString("status", "INSTALLED");
break;
case ServiceWorkerVersion::ACTIVATING:
info->SetString("status", "ACTIVATING");
break;
case ServiceWorkerVersion::ACTIVE:
info->SetString("status", "ACTIVE");
break;
case ServiceWorkerVersion::DEACTIVATED:
info->SetString("status", "DEACTIVATED");
break;
}
info->SetInteger("process_id", version.process_id);
info->SetInteger("thread_id", version.thread_id);
}
}
void ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations(
const base::FilePath& context_path,
const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(
&ServiceWorkerInternalsUI::OperationProxy::OnHaveRegistrations,
this,
context_path,
registrations));
return;
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
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_ && !result.empty())
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;
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
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);
}
void ServiceWorkerInternalsUI::OperationProxy::DispatchSyncEventToActiveWorker(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (status == SERVICE_WORKER_OK && registration->active_version() &&
registration->active_version()->status() ==
ServiceWorkerVersion::ACTIVE) {
registration->active_version()->DispatchSyncEvent(base::Bind(
&ServiceWorkerInternalsUI::OperationProxy::OperationComplete, this));
return;
}
OperationComplete(SERVICE_WORKER_ERROR_FAILED);
}
}