#include "content/browser/devtools/devtools_manager_impl.h"
#include "content/browser/devtools/devtools_protocol.h"
#include "content/browser/devtools/devtools_protocol_constants.h"
+#include "content/browser/devtools/embedded_worker_devtools_agent_host.h"
#include "content/browser/devtools/ipc_devtools_agent_host.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
#include "content/common/devtools_messages.h"
namespace content {
-namespace {
-
-bool SendMessageToWorker(
- const EmbeddedWorkerDevToolsManager::WorkerId& worker_id,
- IPC::Message* message) {
- RenderProcessHost* host = RenderProcessHost::FromID(worker_id.first);
- if (!host) {
- delete message;
- return false;
- }
- message->set_routing_id(worker_id.second);
- host->Send(message);
- return true;
-}
-
-} // namespace
-
-EmbeddedWorkerDevToolsManager::WorkerInfo::WorkerInfo(
- const SharedWorkerInstance& instance)
- : shared_worker_instance_(new SharedWorkerInstance(instance)),
- state_(WORKER_UNINSPECTED),
- agent_host_(NULL) {
-}
-
-EmbeddedWorkerDevToolsManager::WorkerInfo::WorkerInfo(
- const base::FilePath& storage_partition_path,
- const GURL& service_worker_scope)
- : storage_partition_path_(new base::FilePath(storage_partition_path)),
- service_worker_scope_(new GURL(service_worker_scope)),
- state_(WORKER_UNINSPECTED),
- agent_host_(NULL) {
+// Called on the UI thread.
+// static
+scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForWorker(
+ int worker_process_id,
+ int worker_route_id) {
+ return EmbeddedWorkerDevToolsManager::GetInstance()
+ ->GetDevToolsAgentHostForWorker(worker_process_id, worker_route_id);
}
-bool EmbeddedWorkerDevToolsManager::WorkerInfo::Matches(
- const SharedWorkerInstance& other) {
- if (!shared_worker_instance_)
- return false;
- return shared_worker_instance_->Matches(other);
+EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
+ const ServiceWorkerContextCore* const service_worker_context,
+ int64 service_worker_version_id)
+ : service_worker_context_(service_worker_context),
+ service_worker_version_id_(service_worker_version_id) {
}
-bool EmbeddedWorkerDevToolsManager::WorkerInfo::Matches(
- const base::FilePath& other_storage_partition_path,
- const GURL& other_service_worker_scope) {
- if (!storage_partition_path_ || !service_worker_scope_)
- return false;
- return *storage_partition_path_ == other_storage_partition_path &&
- *service_worker_scope_ == other_service_worker_scope;
+EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
+ const ServiceWorkerIdentifier& other)
+ : service_worker_context_(other.service_worker_context_),
+ service_worker_version_id_(other.service_worker_version_id_) {
}
-EmbeddedWorkerDevToolsManager::WorkerInfo::~WorkerInfo() {
+bool EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::Matches(
+ const ServiceWorkerIdentifier& other) const {
+ return service_worker_context_ == other.service_worker_context_ &&
+ service_worker_version_id_ == other.service_worker_version_id_;
}
-class EmbeddedWorkerDevToolsManager::EmbeddedWorkerDevToolsAgentHost
- : public IPCDevToolsAgentHost,
- public IPC::Listener {
- public:
- explicit EmbeddedWorkerDevToolsAgentHost(WorkerId worker_id)
- : worker_id_(worker_id), worker_attached_(true) {
- AddRef();
- if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
- host->AddRoute(worker_id_.second, this);
- }
-
- // IPCDevToolsAgentHost implementation.
- virtual void SendMessageToAgent(IPC::Message* message) OVERRIDE {
- if (worker_attached_)
- SendMessageToWorker(worker_id_, message);
- else
- delete message;
- }
- virtual void OnClientAttached() OVERRIDE {}
- virtual void OnClientDetached() OVERRIDE {}
-
- // IPC::Listener implementation.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerDevToolsAgentHost, msg)
- IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
- OnDispatchOnInspectorFrontend)
- IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
- OnSaveAgentRuntimeState)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
- }
-
- void ReattachToWorker(WorkerId worker_id) {
- CHECK(!worker_attached_);
- worker_attached_ = true;
- worker_id_ = worker_id;
- AddRef();
- if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
- host->AddRoute(worker_id_.second, this);
- Reattach(state_);
- }
-
- void DetachFromWorker() {
- CHECK(worker_attached_);
- worker_attached_ = false;
- if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
- host->RemoveRoute(worker_id_.second);
- Release();
- }
-
- WorkerId worker_id() const { return worker_id_; }
-
- private:
- virtual ~EmbeddedWorkerDevToolsAgentHost() {
- CHECK(!worker_attached_);
- EmbeddedWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(
- this);
- }
-
- void OnDispatchOnInspectorFrontend(const std::string& message) {
- DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(this,
- message);
- }
-
- void OnSaveAgentRuntimeState(const std::string& state) { state_ = state; }
-
- WorkerId worker_id_;
- bool worker_attached_;
- std::string state_;
- DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerDevToolsAgentHost);
-};
-
// static
EmbeddedWorkerDevToolsManager* EmbeddedWorkerDevToolsManager::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DevToolsAgentHost* EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForWorker(
int worker_process_id,
int worker_route_id) {
- WorkerId id(worker_process_id, worker_route_id);
-
- WorkerInfoMap::iterator it = workers_.find(id);
- if (it == workers_.end())
- return NULL;
-
- WorkerInfo* info = it->second;
- if (info->state() != WORKER_UNINSPECTED)
- return info->agent_host();
-
- EmbeddedWorkerDevToolsAgentHost* agent_host =
- new EmbeddedWorkerDevToolsAgentHost(id);
- info->set_agent_host(agent_host);
- info->set_state(WORKER_INSPECTED);
- return agent_host;
-}
-
-DevToolsAgentHost*
-EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForServiceWorker(
- const base::FilePath& storage_partition_path,
- const GURL& service_worker_scope) {
- WorkerInfoMap::iterator it = FindExistingServiceWorkerInfo(
- storage_partition_path, service_worker_scope);
- if (it == workers_.end())
- return NULL;
- return GetDevToolsAgentHostForWorker(it->first.first, it->first.second);
+ AgentHostMap::iterator it = workers_.find(
+ WorkerId(worker_process_id, worker_route_id));
+ return it == workers_.end() ? NULL : it->second;
}
-EmbeddedWorkerDevToolsManager::EmbeddedWorkerDevToolsManager() {
+EmbeddedWorkerDevToolsManager::EmbeddedWorkerDevToolsManager()
+ : debug_service_worker_on_start_(false) {
}
EmbeddedWorkerDevToolsManager::~EmbeddedWorkerDevToolsManager() {
const SharedWorkerInstance& instance) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const WorkerId id(worker_process_id, worker_route_id);
- WorkerInfoMap::iterator it = FindExistingSharedWorkerInfo(instance);
+ AgentHostMap::iterator it = FindExistingSharedWorkerAgentHost(instance);
if (it == workers_.end()) {
- scoped_ptr<WorkerInfo> info(new WorkerInfo(instance));
- workers_.set(id, info.Pass());
+ workers_[id] = new EmbeddedWorkerDevToolsAgentHost(id, instance);
return false;
}
- MoveToPausedState(id, it);
+ WorkerRestarted(id, it);
return true;
}
bool EmbeddedWorkerDevToolsManager::ServiceWorkerCreated(
int worker_process_id,
int worker_route_id,
- const base::FilePath& storage_partition_path,
- const GURL& service_worker_scope) {
+ const ServiceWorkerIdentifier& service_worker_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const WorkerId id(worker_process_id, worker_route_id);
- WorkerInfoMap::iterator it = FindExistingServiceWorkerInfo(
- storage_partition_path, service_worker_scope);
+ AgentHostMap::iterator it =
+ FindExistingServiceWorkerAgentHost(service_worker_id);
if (it == workers_.end()) {
- scoped_ptr<WorkerInfo> info(
- new WorkerInfo(storage_partition_path, service_worker_scope));
- workers_.set(id, info.Pass());
- return false;
+ workers_[id] = new EmbeddedWorkerDevToolsAgentHost(
+ id, service_worker_id, debug_service_worker_on_start_);
+ return debug_service_worker_on_start_;
}
- MoveToPausedState(id, it);
+ WorkerRestarted(id, it);
return true;
}
int worker_route_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const WorkerId id(worker_process_id, worker_route_id);
- WorkerInfoMap::iterator it = workers_.find(id);
+ AgentHostMap::iterator it = workers_.find(id);
DCHECK(it != workers_.end());
- WorkerInfo* info = it->second;
- switch (info->state()) {
- case WORKER_UNINSPECTED:
- workers_.erase(it);
- break;
- case WORKER_INSPECTED: {
- EmbeddedWorkerDevToolsAgentHost* agent_host = info->agent_host();
- if (!agent_host->IsAttached()) {
- scoped_ptr<WorkerInfo> worker_info = workers_.take_and_erase(it);
- agent_host->DetachFromWorker();
- return;
- }
- info->set_state(WORKER_TERMINATED);
- // Client host is debugging this worker agent host.
- std::string notification =
- DevToolsProtocol::CreateNotification(
- devtools::Worker::disconnectedFromWorker::kName, NULL)
- ->Serialize();
- DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(
- agent_host, notification);
- agent_host->DetachFromWorker();
- break;
- }
- case WORKER_TERMINATED:
- NOTREACHED();
- break;
- case WORKER_PAUSED: {
- scoped_ptr<WorkerInfo> worker_info = workers_.take_and_erase(it);
- worker_info->set_state(WORKER_TERMINATED);
- const WorkerId old_id = worker_info->agent_host()->worker_id();
- workers_.set(old_id, worker_info.Pass());
- break;
- }
- }
+ it->second->WorkerDestroyed();
}
void EmbeddedWorkerDevToolsManager::WorkerContextStarted(int worker_process_id,
int worker_route_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const WorkerId id(worker_process_id, worker_route_id);
- WorkerInfoMap::iterator it = workers_.find(id);
+ AgentHostMap::iterator it = workers_.find(id);
DCHECK(it != workers_.end());
- WorkerInfo* info = it->second;
- if (info->state() != WORKER_PAUSED)
- return;
- info->agent_host()->ReattachToWorker(id);
- info->set_state(WORKER_INSPECTED);
+ it->second->WorkerContextStarted();
}
-void EmbeddedWorkerDevToolsManager::RemoveInspectedWorkerData(
- EmbeddedWorkerDevToolsAgentHost* agent_host) {
+void EmbeddedWorkerDevToolsManager::RemoveInspectedWorkerData(WorkerId id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- const WorkerId id(agent_host->worker_id());
- scoped_ptr<WorkerInfo> worker_info = workers_.take_and_erase(id);
- if (worker_info) {
- DCHECK_EQ(WORKER_TERMINATED, worker_info->state());
- return;
- }
- for (WorkerInfoMap::iterator it = workers_.begin(); it != workers_.end();
- ++it) {
- if (it->second->agent_host() == agent_host) {
- DCHECK_EQ(WORKER_PAUSED, it->second->state());
- SendMessageToWorker(
- it->first,
- new DevToolsAgentMsg_ResumeWorkerContext(it->first.second));
- it->second->set_agent_host(NULL);
- it->second->set_state(WORKER_UNINSPECTED);
- return;
- }
- }
+ workers_.erase(id);
}
-EmbeddedWorkerDevToolsManager::WorkerInfoMap::iterator
-EmbeddedWorkerDevToolsManager::FindExistingSharedWorkerInfo(
+EmbeddedWorkerDevToolsManager::AgentHostMap::iterator
+EmbeddedWorkerDevToolsManager::FindExistingSharedWorkerAgentHost(
const SharedWorkerInstance& instance) {
- WorkerInfoMap::iterator it = workers_.begin();
+ AgentHostMap::iterator it = workers_.begin();
for (; it != workers_.end(); ++it) {
if (it->second->Matches(instance))
break;
return it;
}
-EmbeddedWorkerDevToolsManager::WorkerInfoMap::iterator
-EmbeddedWorkerDevToolsManager::FindExistingServiceWorkerInfo(
- const base::FilePath& storage_partition_path,
- const GURL& service_worker_scope) {
- WorkerInfoMap::iterator it = workers_.begin();
+EmbeddedWorkerDevToolsManager::AgentHostMap::iterator
+EmbeddedWorkerDevToolsManager::FindExistingServiceWorkerAgentHost(
+ const ServiceWorkerIdentifier& service_worker_id) {
+ AgentHostMap::iterator it = workers_.begin();
for (; it != workers_.end(); ++it) {
- if (it->second->Matches(storage_partition_path, service_worker_scope))
+ if (it->second->Matches(service_worker_id))
break;
}
return it;
}
-void EmbeddedWorkerDevToolsManager::MoveToPausedState(
+void EmbeddedWorkerDevToolsManager::WorkerRestarted(
const WorkerId& id,
- const WorkerInfoMap::iterator& it) {
- DCHECK_EQ(WORKER_TERMINATED, it->second->state());
- scoped_ptr<WorkerInfo> info = workers_.take_and_erase(it);
- info->set_state(WORKER_PAUSED);
- workers_.set(id, info.Pass());
+ const AgentHostMap::iterator& it) {
+ EmbeddedWorkerDevToolsAgentHost* agent_host = it->second;
+ agent_host->WorkerRestarted(id);
+ workers_.erase(it);
+ workers_[id] = agent_host;
}
void EmbeddedWorkerDevToolsManager::ResetForTesting() {