summaryrefslogtreecommitdiffstats
path: root/content/browser/debugger/worker_devtools_manager.cc
diff options
context:
space:
mode:
authoryurys@chromium.org <yurys@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-08 06:23:46 +0000
committeryurys@chromium.org <yurys@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-08 06:23:46 +0000
commitb3762af2f645ce363f4bc5fd99fbda14260c11fe (patch)
tree9d7acef3359d4ea40fd2b4c2e7ce634863c1b72b /content/browser/debugger/worker_devtools_manager.cc
parentbfe9d6d536336f7a5a88279cf6686756e6b95ab2 (diff)
downloadchromium_src-b3762af2f645ce363f4bc5fd99fbda14260c11fe.zip
chromium_src-b3762af2f645ce363f4bc5fd99fbda14260c11fe.tar.gz
chromium_src-b3762af2f645ce363f4bc5fd99fbda14260c11fe.tar.bz2
DevTools: introduce WorkderDevToolsAgentHost
We already have RenderViewDevToolsAgent host for inspected pages. This patch introduces WorkderDevToolsAgentHost which implements DevToolsAgentHost interface for inspected shared workers. Also this patch moves part of devtools message routing for workers to DevToolsManager. BUG=None TEST=Existing DevTools tests Review URL: http://codereview.chromium.org/7737026 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100112 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/debugger/worker_devtools_manager.cc')
-rw-r--r--content/browser/debugger/worker_devtools_manager.cc337
1 files changed, 337 insertions, 0 deletions
diff --git a/content/browser/debugger/worker_devtools_manager.cc b/content/browser/debugger/worker_devtools_manager.cc
new file mode 100644
index 0000000..573ef3f
--- /dev/null
+++ b/content/browser/debugger/worker_devtools_manager.cc
@@ -0,0 +1,337 @@
+// Copyright (c) 2011 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/debugger/worker_devtools_manager.h"
+
+#include <list>
+#include <map>
+
+#include "base/tuple.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/debugger/devtools_agent_host.h"
+#include "content/browser/debugger/devtools_manager.h"
+#include "content/browser/debugger/worker_devtools_message_filter.h"
+#include "content/browser/worker_host/worker_process_host.h"
+#include "content/common/content_notification_types.h"
+#include "content/common/devtools_messages.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
+#include "content/common/notification_service.h"
+
+namespace {
+typedef std::pair<int, int> WorkerId;
+}
+
+class WorkerDevToolsManager::AgentHosts : private NotificationObserver {
+public:
+ static void Add(WorkerId id, WorkerDevToolsAgentHost* host) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!instance_)
+ instance_ = new AgentHosts();
+ instance_->map_[id] = host;
+ }
+ static void Remove(WorkerId id) {
+ DCHECK(instance_);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ Instances& map = instance_->map_;
+ map.erase(id);
+ if (map.empty()) {
+ delete instance_;
+ instance_ = NULL;
+ }
+ }
+
+ static WorkerDevToolsAgentHost* GetAgentHost(WorkerId id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!instance_)
+ return NULL;
+ Instances& map = instance_->map_;
+ Instances::iterator it = map.find(id);
+ if (it == map.end())
+ return NULL;
+ return it->second;
+ }
+
+private:
+ AgentHosts() {
+ registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING,
+ NotificationService::AllSources());
+ }
+ ~AgentHosts() {}
+
+ // NotificationObserver implementation.
+ virtual void Observe(int type,
+ const NotificationSource&,
+ const NotificationDetails&) OVERRIDE;
+
+ static AgentHosts* instance_;
+ typedef std::map<WorkerId, WorkerDevToolsAgentHost*> Instances;
+ Instances map_;
+ NotificationRegistrar registrar_;
+};
+
+WorkerDevToolsManager::AgentHosts*
+ WorkerDevToolsManager::AgentHosts::instance_ = NULL;
+
+
+class WorkerDevToolsManager::WorkerDevToolsAgentHost
+ : public DevToolsAgentHost {
+ public:
+ explicit WorkerDevToolsAgentHost(WorkerId worker_id)
+ : worker_id_(worker_id) {
+ AgentHosts::Add(worker_id, this);
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableFunction(
+ &RegisterAgent,
+ worker_id.first,
+ worker_id.second));
+ }
+
+ void WorkerDestroyed() {
+ NotifyCloseListener();
+ delete this;
+ }
+
+ private:
+ virtual ~WorkerDevToolsAgentHost() {
+ AgentHosts::Remove(worker_id_);
+ }
+
+ static void RegisterAgent(
+ int worker_process_id,
+ int worker_route_id) {
+ WorkerDevToolsManager::GetInstance()->RegisterDevToolsAgentHostForWorker(
+ worker_process_id, worker_route_id);
+ }
+
+ static void ForwardToWorkerDevToolsAgent(
+ int worker_process_id,
+ int worker_route_id,
+ const IPC::Message& message) {
+ WorkerDevToolsManager::GetInstance()->ForwardToWorkerDevToolsAgent(
+ worker_process_id, worker_route_id, message);
+ }
+
+ // DevToolsAgentHost implementation.
+ virtual void SendMessageToAgent(IPC::Message* message) OVERRIDE {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(
+ &WorkerDevToolsAgentHost::ForwardToWorkerDevToolsAgent,
+ worker_id_.first,
+ worker_id_.second,
+ *message));
+ }
+ virtual void NotifyClientClosing() OVERRIDE {}
+ virtual int GetRenderProcessId() OVERRIDE { return -1; }
+
+ WorkerId worker_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(WorkerDevToolsAgentHost);
+};
+
+void WorkerDevToolsManager::AgentHosts::Observe(int type,
+ const NotificationSource&,
+ const NotificationDetails&) {
+ DCHECK(type == content::NOTIFICATION_APP_TERMINATING);
+ Instances copy(map_);
+ for (Instances::iterator it = copy.begin(); it != copy.end(); ++it)
+ it->second->WorkerDestroyed();
+ DCHECK(!instance_);
+}
+
+class WorkerDevToolsManager::InspectedWorkersList {
+ public:
+ InspectedWorkersList() {}
+
+ void AddInstance(WorkerProcessHost* host, int route_id) {
+ DCHECK(!Contains(host->id(), route_id));
+ map_.push_back(Entry(host, route_id));
+ }
+
+ bool Contains(int host_id, int route_id) {
+ return FindHost(host_id, route_id) != NULL;
+ }
+
+ WorkerProcessHost* FindHost(int host_id, int route_id) {
+ Entries::iterator it = FindEntry(host_id, route_id);
+ if (it == map_.end())
+ return NULL;
+ return it->host;
+ }
+
+ WorkerProcessHost* RemoveInstance(int host_id, int route_id) {
+ Entries::iterator it = FindEntry(host_id, route_id);
+ if (it == map_.end())
+ return NULL;
+ WorkerProcessHost* host = it->host;
+ map_.erase(it);
+ return host;
+ }
+
+ void WorkerDevToolsMessageFilterClosing(int worker_process_id) {
+ Entries::iterator it = map_.begin();
+ while (it != map_.end()) {
+ if (it->host->id() == worker_process_id) {
+ NotifyWorkerDestroyedOnIOThread(
+ it->host->id(),
+ it->route_id);
+ it = map_.erase(it);
+ } else
+ ++it;
+ }
+ }
+
+ private:
+ struct Entry {
+ Entry(WorkerProcessHost* host, int route_id)
+ : host(host),
+ route_id(route_id) {}
+ WorkerProcessHost* const host;
+ int const route_id;
+ };
+ typedef std::list<Entry> Entries;
+
+ Entries::iterator FindEntry(int host_id, int route_id) {
+ Entries::iterator it = map_.begin();
+ while (it != map_.end()) {
+ if (it->host->id() == host_id && it->route_id == route_id)
+ break;
+ ++it;
+ }
+ return it;
+ }
+
+ Entries map_;
+ DISALLOW_COPY_AND_ASSIGN(InspectedWorkersList);
+};
+
+// static
+WorkerDevToolsManager* WorkerDevToolsManager::GetInstance() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ return Singleton<WorkerDevToolsManager>::get();
+}
+
+// static
+DevToolsAgentHost* WorkerDevToolsManager::GetDevToolsAgentHostForWorker(
+ int worker_process_id,
+ int worker_route_id) {
+ WorkerId id(worker_process_id, worker_route_id);
+ WorkerDevToolsAgentHost* result = AgentHosts::GetAgentHost(id);
+ if (!result)
+ result = new WorkerDevToolsAgentHost(id);
+ return result;
+}
+
+WorkerDevToolsManager::WorkerDevToolsManager()
+ : inspected_workers_(new InspectedWorkersList()) {
+}
+
+WorkerDevToolsManager::~WorkerDevToolsManager() {
+}
+
+static WorkerProcessHost* FindWorkerProcessHostForWorker(
+ int worker_process_id,
+ int worker_route_id) {
+ BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ for (; !iter.Done(); ++iter) {
+ if (iter->id() != worker_process_id)
+ continue;
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ const WorkerProcessHost::Instances& instances = worker->instances();
+ for (WorkerProcessHost::Instances::const_iterator i = instances.begin();
+ i != instances.end(); ++i) {
+ if (i->shared() && i->worker_route_id() == worker_route_id)
+ return worker;
+ }
+ return NULL;
+ }
+ return NULL;
+}
+
+void WorkerDevToolsManager::RegisterDevToolsAgentHostForWorker(
+ int worker_process_id,
+ int worker_route_id) {
+ WorkerProcessHost* host = FindWorkerProcessHostForWorker(
+ worker_process_id,
+ worker_route_id);
+ if (host)
+ inspected_workers_->AddInstance(host, worker_route_id);
+ else
+ NotifyWorkerDestroyedOnIOThread(worker_process_id, worker_route_id);
+}
+
+void WorkerDevToolsManager::ForwardToDevToolsClient(
+ int worker_process_id,
+ int worker_route_id,
+ const IPC::Message& message) {
+ if (!inspected_workers_->Contains(worker_process_id, worker_route_id)) {
+ NOTREACHED();
+ return;
+ }
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(
+ ForwardToDevToolsClientOnUIThread,
+ worker_process_id,
+ worker_route_id,
+ message));
+}
+
+void WorkerDevToolsManager::WorkerProcessDestroying(
+ int worker_process_id) {
+ inspected_workers_->WorkerDevToolsMessageFilterClosing(
+ worker_process_id);
+}
+
+void WorkerDevToolsManager::ForwardToWorkerDevToolsAgent(
+ int worker_process_id,
+ int worker_route_id,
+ const IPC::Message& message) {
+ WorkerProcessHost* host = inspected_workers_->FindHost(
+ worker_process_id,
+ worker_route_id);
+ if (!host)
+ return;
+ IPC::Message* msg = new IPC::Message(message);
+ msg->set_routing_id(worker_route_id);
+ host->Send(msg);
+}
+
+// static
+void WorkerDevToolsManager::ForwardToDevToolsClientOnUIThread(
+ int worker_process_id,
+ int worker_route_id,
+ const IPC::Message& message) {
+ WorkerDevToolsAgentHost* agent_host = AgentHosts::GetAgentHost(WorkerId(
+ worker_process_id,
+ worker_route_id));
+ if (!agent_host)
+ return;
+ DevToolsManager::GetInstance()->ForwardToDevToolsClient(agent_host, message);
+}
+
+// static
+void WorkerDevToolsManager::NotifyWorkerDestroyedOnIOThread(
+ int worker_process_id,
+ int worker_route_id) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(
+ &WorkerDevToolsManager::NotifyWorkerDestroyedOnUIThread,
+ worker_process_id,
+ worker_route_id));
+}
+
+// static
+void WorkerDevToolsManager::NotifyWorkerDestroyedOnUIThread(
+ int worker_process_id,
+ int worker_route_id) {
+ WorkerDevToolsAgentHost* host =
+ AgentHosts::GetAgentHost(WorkerId(worker_process_id, worker_route_id));
+ if (host)
+ host->WorkerDestroyed();
+}