summaryrefslogtreecommitdiffstats
path: root/chrome/browser/worker_host
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/worker_host')
-rw-r--r--chrome/browser/worker_host/message_port_dispatcher.cc292
-rw-r--r--chrome/browser/worker_host/message_port_dispatcher.h93
-rw-r--r--chrome/browser/worker_host/message_port_service.cc236
-rw-r--r--chrome/browser/worker_host/message_port_service.h75
-rw-r--r--chrome/browser/worker_host/worker_document_set.cc35
-rw-r--r--chrome/browser/worker_host/worker_document_set.h41
-rw-r--r--chrome/browser/worker_host/worker_message_filter.cc116
-rw-r--r--chrome/browser/worker_host/worker_message_filter.h62
-rw-r--r--chrome/browser/worker_host/worker_process_host.cc449
-rw-r--r--chrome/browser/worker_host/worker_process_host.h134
-rw-r--r--chrome/browser/worker_host/worker_service.cc515
-rw-r--r--chrome/browser/worker_host/worker_service.h119
12 files changed, 1038 insertions, 1129 deletions
diff --git a/chrome/browser/worker_host/message_port_dispatcher.cc b/chrome/browser/worker_host/message_port_dispatcher.cc
deleted file mode 100644
index 3fedd67..0000000
--- a/chrome/browser/worker_host/message_port_dispatcher.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/worker_host/message_port_dispatcher.h"
-
-#include "base/callback.h"
-#include "base/singleton.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/browser/worker_host/worker_process_host.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/worker_messages.h"
-
-struct MessagePortDispatcher::MessagePort {
- // sender and route_id are what we need to send messages to the port.
- IPC::Message::Sender* sender;
- int route_id;
- // A function pointer to generate a new route id for the sender above.
- // Owned by "sender" above, so don't delete.
- CallbackWithReturnValue<int>::Type* next_routing_id;
- // A globally unique id for this message port.
- int message_port_id;
- // The globally unique id of the entangled message port.
- int entangled_message_port_id;
- // If true, all messages to this message port are queued and not delivered.
- bool queue_messages;
- QueuedMessages queued_messages;
-};
-
-MessagePortDispatcher* MessagePortDispatcher::GetInstance() {
- return Singleton<MessagePortDispatcher>::get();
-}
-
-MessagePortDispatcher::MessagePortDispatcher()
- : next_message_port_id_(0),
- sender_(NULL),
- next_routing_id_(NULL) {
- // Receive a notification if a message filter or WorkerProcessHost is deleted.
- registrar_.Add(this, NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
- NotificationService::AllSources());
-
- registrar_.Add(this, NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
- NotificationService::AllSources());
-}
-
-MessagePortDispatcher::~MessagePortDispatcher() {
-}
-
-bool MessagePortDispatcher::OnMessageReceived(
- const IPC::Message& message,
- IPC::Message::Sender* sender,
- CallbackWithReturnValue<int>::Type* next_routing_id,
- bool* message_was_ok) {
- sender_ = sender;
- next_routing_id_ = next_routing_id;
-
- bool handled = true;
- *message_was_ok = true;
-
- IPC_BEGIN_MESSAGE_MAP_EX(MessagePortDispatcher, message, *message_was_ok)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_CreateMessagePort, OnCreate)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_DestroyMessagePort, OnDestroy)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_Entangle, OnEntangle)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_PostMessage, OnPostMessage)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_QueueMessages, OnQueueMessages)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_SendQueuedMessages,
- OnSendQueuedMessages)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP_EX()
-
- sender_ = NULL;
- next_routing_id_ = NULL;
-
- return handled;
-}
-
-void MessagePortDispatcher::UpdateMessagePort(
- int message_port_id,
- IPC::Message::Sender* sender,
- int routing_id,
- CallbackWithReturnValue<int>::Type* next_routing_id) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- MessagePort& port = message_ports_[message_port_id];
- port.sender = sender;
- port.route_id = routing_id;
- port.next_routing_id = next_routing_id;
-}
-
-bool MessagePortDispatcher::Send(IPC::Message* message) {
- return sender_->Send(message);
-}
-
-void MessagePortDispatcher::OnCreate(int *route_id,
- int* message_port_id) {
- *message_port_id = ++next_message_port_id_;
- *route_id = next_routing_id_->Run();
-
- MessagePort port;
- port.sender = sender_;
- port.route_id = *route_id;
- port.next_routing_id = next_routing_id_;
- port.message_port_id = *message_port_id;
- port.entangled_message_port_id = MSG_ROUTING_NONE;
- port.queue_messages = false;
- message_ports_[*message_port_id] = port;
-}
-
-void MessagePortDispatcher::OnDestroy(int message_port_id) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- DCHECK(message_ports_[message_port_id].queued_messages.empty());
- Erase(message_port_id);
-}
-
-void MessagePortDispatcher::OnEntangle(int local_message_port_id,
- int remote_message_port_id) {
- if (!message_ports_.count(local_message_port_id) ||
- !message_ports_.count(remote_message_port_id)) {
- NOTREACHED();
- return;
- }
-
- DCHECK(message_ports_[remote_message_port_id].entangled_message_port_id ==
- MSG_ROUTING_NONE);
- message_ports_[remote_message_port_id].entangled_message_port_id =
- local_message_port_id;
-}
-
-void MessagePortDispatcher::OnPostMessage(
- int sender_message_port_id,
- const string16& message,
- const std::vector<int>& sent_message_port_ids) {
- if (!message_ports_.count(sender_message_port_id)) {
- NOTREACHED();
- return;
- }
-
- int entangled_message_port_id =
- message_ports_[sender_message_port_id].entangled_message_port_id;
- if (entangled_message_port_id == MSG_ROUTING_NONE)
- return; // Process could have crashed.
-
- if (!message_ports_.count(entangled_message_port_id)) {
- NOTREACHED();
- return;
- }
-
- PostMessageTo(entangled_message_port_id, message, sent_message_port_ids);
-}
-
-void MessagePortDispatcher::PostMessageTo(
- int message_port_id,
- const string16& message,
- const std::vector<int>& sent_message_port_ids) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- if (!message_ports_.count(sent_message_port_ids[i])) {
- NOTREACHED();
- return;
- }
- }
-
- MessagePort& entangled_port = message_ports_[message_port_id];
-
- std::vector<MessagePort*> sent_ports(sent_message_port_ids.size());
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- sent_ports[i] = &message_ports_[sent_message_port_ids[i]];
- sent_ports[i]->queue_messages = true;
- }
-
- if (entangled_port.queue_messages) {
- entangled_port.queued_messages.push_back(
- std::make_pair(message, sent_message_port_ids));
- } else {
- // If a message port was sent around, the new location will need a routing
- // id. Instead of having the created port send us a sync message to get it,
- // send along with the message.
- std::vector<int> new_routing_ids(sent_message_port_ids.size());
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- new_routing_ids[i] = entangled_port.next_routing_id->Run();
- sent_ports[i]->sender = entangled_port.sender;
-
- // Update the entry for the sent port as it can be in a different process.
- sent_ports[i]->route_id = new_routing_ids[i];
- }
-
- if (entangled_port.sender) {
- // Now send the message to the entangled port.
- IPC::Message* ipc_msg = new WorkerProcessMsg_Message(
- entangled_port.route_id, message, sent_message_port_ids,
- new_routing_ids);
- entangled_port.sender->Send(ipc_msg);
- }
- }
-}
-
-void MessagePortDispatcher::OnQueueMessages(int message_port_id) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- MessagePort& port = message_ports_[message_port_id];
- if (port.sender) {
- port.sender->Send(new WorkerProcessMsg_MessagesQueued(port.route_id));
- port.queue_messages = true;
- port.sender = NULL;
- }
-}
-
-void MessagePortDispatcher::OnSendQueuedMessages(
- int message_port_id,
- const QueuedMessages& queued_messages) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- // Send the queued messages to the port again. This time they'll reach the
- // new location.
- MessagePort& port = message_ports_[message_port_id];
- port.queue_messages = false;
- port.queued_messages.insert(port.queued_messages.begin(),
- queued_messages.begin(),
- queued_messages.end());
- SendQueuedMessagesIfPossible(message_port_id);
-}
-
-void MessagePortDispatcher::SendQueuedMessagesIfPossible(int message_port_id) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- MessagePort& port = message_ports_[message_port_id];
- if (port.queue_messages || !port.sender)
- return;
-
- for (QueuedMessages::iterator iter = port.queued_messages.begin();
- iter != port.queued_messages.end(); ++iter) {
- PostMessageTo(message_port_id, iter->first, iter->second);
- }
- port.queued_messages.clear();
-}
-
-void MessagePortDispatcher::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- IPC::Message::Sender* sender = NULL;
- if (type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN) {
- sender = Source<ResourceMessageFilter>(source).ptr();
- } else if (type.value == NotificationType::WORKER_PROCESS_HOST_SHUTDOWN) {
- sender = Source<WorkerProcessHost>(source).ptr();
- } else {
- NOTREACHED();
- }
-
- // Check if the (possibly) crashed process had any message ports.
- for (MessagePorts::iterator iter = message_ports_.begin();
- iter != message_ports_.end();) {
- MessagePorts::iterator cur_item = iter++;
- if (cur_item->second.sender == sender) {
- Erase(cur_item->first);
- }
- }
-}
-
-void MessagePortDispatcher::Erase(int message_port_id) {
- MessagePorts::iterator erase_item = message_ports_.find(message_port_id);
- DCHECK(erase_item != message_ports_.end());
-
- int entangled_id = erase_item->second.entangled_message_port_id;
- if (entangled_id != MSG_ROUTING_NONE) {
- // Do the disentanglement (and be paranoid about the other side existing
- // just in case something unusual happened during entanglement).
- if (message_ports_.count(entangled_id)) {
- message_ports_[entangled_id].entangled_message_port_id = MSG_ROUTING_NONE;
- }
- }
- message_ports_.erase(erase_item);
-}
diff --git a/chrome/browser/worker_host/message_port_dispatcher.h b/chrome/browser/worker_host/message_port_dispatcher.h
deleted file mode 100644
index 566416b..0000000
--- a/chrome/browser/worker_host/message_port_dispatcher.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2009 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.
-
-#ifndef CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
-#define CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
-#pragma once
-
-#include <map>
-#include <utility>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/singleton.h"
-#include "base/string16.h"
-#include "base/task.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "ipc/ipc_message.h"
-
-class MessagePortDispatcher : public NotificationObserver {
- public:
- typedef std::vector<std::pair<string16, std::vector<int> > > QueuedMessages;
-
- // Returns the MessagePortDispatcher singleton.
- static MessagePortDispatcher* GetInstance();
-
- bool OnMessageReceived(const IPC::Message& message,
- IPC::Message::Sender* sender,
- CallbackWithReturnValue<int>::Type* next_routing_id,
- bool* message_was_ok);
-
- // Updates the information needed to reach a message port when it's sent to a
- // (possibly different) process.
- void UpdateMessagePort(
- int message_port_id,
- IPC::Message::Sender* sender,
- int routing_id,
- CallbackWithReturnValue<int>::Type* next_routing_id);
-
- // Attempts to send the queued messages for a message port.
- void SendQueuedMessagesIfPossible(int message_port_id);
-
- bool Send(IPC::Message* message);
-
- private:
- friend struct DefaultSingletonTraits<MessagePortDispatcher>;
-
- MessagePortDispatcher();
- ~MessagePortDispatcher();
-
- // Message handlers.
- void OnCreate(int* route_id, int* message_port_id);
- void OnDestroy(int message_port_id);
- void OnEntangle(int local_message_port_id, int remote_message_port_id);
- void OnPostMessage(int sender_message_port_id,
- const string16& message,
- const std::vector<int>& sent_message_port_ids);
- void OnQueueMessages(int message_port_id);
- void OnSendQueuedMessages(int message_port_id,
- const QueuedMessages& queued_messages);
-
- void PostMessageTo(int message_port_id,
- const string16& message,
- const std::vector<int>& sent_message_port_ids);
-
- // NotificationObserver interface.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Handles the details of removing a message port id. Before calling this,
- // verify that the message port id exists.
- void Erase(int message_port_id);
-
- struct MessagePort;
- typedef std::map<int, MessagePort> MessagePorts;
- MessagePorts message_ports_;
-
- // We need globally unique identifiers for each message port.
- int next_message_port_id_;
-
- // Valid only during IPC message dispatching.
- IPC::Message::Sender* sender_;
- CallbackWithReturnValue<int>::Type* next_routing_id_;
-
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(MessagePortDispatcher);
-};
-
-#endif // CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
diff --git a/chrome/browser/worker_host/message_port_service.cc b/chrome/browser/worker_host/message_port_service.cc
new file mode 100644
index 0000000..6638e71
--- /dev/null
+++ b/chrome/browser/worker_host/message_port_service.cc
@@ -0,0 +1,236 @@
+// Copyright (c) 2009 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 "chrome/browser/worker_host/message_port_service.h"
+
+#include "chrome/browser/worker_host/worker_message_filter.h"
+#include "chrome/common/worker_messages.h"
+
+struct MessagePortService::MessagePort {
+ // |filter| and |route_id| are what we need to send messages to the port.
+ // |filter| is just a weak pointer since we get notified when its process has
+ // gone away and remove it.
+ WorkerMessageFilter* filter;
+ int route_id;
+ // A globally unique id for this message port.
+ int message_port_id;
+ // The globally unique id of the entangled message port.
+ int entangled_message_port_id;
+ // If true, all messages to this message port are queued and not delivered.
+ bool queue_messages;
+ QueuedMessages queued_messages;
+};
+
+MessagePortService* MessagePortService::GetInstance() {
+ return Singleton<MessagePortService>::get();
+}
+
+MessagePortService::MessagePortService()
+ : next_message_port_id_(0) {
+}
+
+MessagePortService::~MessagePortService() {
+}
+
+void MessagePortService::UpdateMessagePort(
+ int message_port_id,
+ WorkerMessageFilter* filter,
+ int routing_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ MessagePort& port = message_ports_[message_port_id];
+ port.filter = filter;
+ port.route_id = routing_id;
+}
+
+void MessagePortService::OnWorkerMessageFilterClosing(
+ WorkerMessageFilter* filter) {
+ // Check if the (possibly) crashed process had any message ports.
+ for (MessagePorts::iterator iter = message_ports_.begin();
+ iter != message_ports_.end();) {
+ MessagePorts::iterator cur_item = iter++;
+ if (cur_item->second.filter == filter) {
+ Erase(cur_item->first);
+ }
+ }
+}
+
+void MessagePortService::Create(int route_id,
+ WorkerMessageFilter* filter,
+ int* message_port_id) {
+ *message_port_id = ++next_message_port_id_;
+
+ MessagePort port;
+ port.filter = filter;
+ port.route_id = route_id;
+ port.message_port_id = *message_port_id;
+ port.entangled_message_port_id = MSG_ROUTING_NONE;
+ port.queue_messages = false;
+ message_ports_[*message_port_id] = port;
+}
+
+void MessagePortService::Destroy(int message_port_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ DCHECK(message_ports_[message_port_id].queued_messages.empty());
+ Erase(message_port_id);
+}
+
+void MessagePortService::Entangle(int local_message_port_id,
+ int remote_message_port_id) {
+ if (!message_ports_.count(local_message_port_id) ||
+ !message_ports_.count(remote_message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ DCHECK(message_ports_[remote_message_port_id].entangled_message_port_id ==
+ MSG_ROUTING_NONE);
+ message_ports_[remote_message_port_id].entangled_message_port_id =
+ local_message_port_id;
+}
+
+void MessagePortService::PostMessage(
+ int sender_message_port_id,
+ const string16& message,
+ const std::vector<int>& sent_message_port_ids) {
+ if (!message_ports_.count(sender_message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ int entangled_message_port_id =
+ message_ports_[sender_message_port_id].entangled_message_port_id;
+ if (entangled_message_port_id == MSG_ROUTING_NONE)
+ return; // Process could have crashed.
+
+ if (!message_ports_.count(entangled_message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ PostMessageTo(entangled_message_port_id, message, sent_message_port_ids);
+}
+
+void MessagePortService::PostMessageTo(
+ int message_port_id,
+ const string16& message,
+ const std::vector<int>& sent_message_port_ids) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+ for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
+ if (!message_ports_.count(sent_message_port_ids[i])) {
+ NOTREACHED();
+ return;
+ }
+ }
+
+ MessagePort& entangled_port = message_ports_[message_port_id];
+
+ std::vector<MessagePort*> sent_ports(sent_message_port_ids.size());
+ for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
+ sent_ports[i] = &message_ports_[sent_message_port_ids[i]];
+ sent_ports[i]->queue_messages = true;
+ }
+
+ if (entangled_port.queue_messages) {
+ entangled_port.queued_messages.push_back(
+ std::make_pair(message, sent_message_port_ids));
+ return;
+ }
+
+ if (!entangled_port.filter) {
+ NOTREACHED();
+ return;
+ }
+
+ // If a message port was sent around, the new location will need a routing
+ // id. Instead of having the created port send us a sync message to get it,
+ // send along with the message.
+ std::vector<int> new_routing_ids(sent_message_port_ids.size());
+ for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
+ new_routing_ids[i] = entangled_port.filter->GetNextRoutingID();
+ sent_ports[i]->filter = entangled_port.filter;
+
+ // Update the entry for the sent port as it can be in a different process.
+ sent_ports[i]->route_id = new_routing_ids[i];
+ }
+
+ // Now send the message to the entangled port.
+ entangled_port.filter->Send(new WorkerProcessMsg_Message(
+ entangled_port.route_id, message, sent_message_port_ids,
+ new_routing_ids));
+}
+
+void MessagePortService::QueueMessages(int message_port_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ MessagePort& port = message_ports_[message_port_id];
+ if (port.filter) {
+ port.filter->Send(new WorkerProcessMsg_MessagesQueued(port.route_id));
+ port.queue_messages = true;
+ port.filter = NULL;
+ }
+}
+
+void MessagePortService::SendQueuedMessages(
+ int message_port_id,
+ const QueuedMessages& queued_messages) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ // Send the queued messages to the port again. This time they'll reach the
+ // new location.
+ MessagePort& port = message_ports_[message_port_id];
+ port.queue_messages = false;
+ port.queued_messages.insert(port.queued_messages.begin(),
+ queued_messages.begin(),
+ queued_messages.end());
+ SendQueuedMessagesIfPossible(message_port_id);
+}
+
+void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ MessagePort& port = message_ports_[message_port_id];
+ if (port.queue_messages || !port.filter)
+ return;
+
+ for (QueuedMessages::iterator iter = port.queued_messages.begin();
+ iter != port.queued_messages.end(); ++iter) {
+ PostMessageTo(message_port_id, iter->first, iter->second);
+ }
+ port.queued_messages.clear();
+}
+
+void MessagePortService::Erase(int message_port_id) {
+ MessagePorts::iterator erase_item = message_ports_.find(message_port_id);
+ DCHECK(erase_item != message_ports_.end());
+
+ int entangled_id = erase_item->second.entangled_message_port_id;
+ if (entangled_id != MSG_ROUTING_NONE) {
+ // Do the disentanglement (and be paranoid about the other side existing
+ // just in case something unusual happened during entanglement).
+ if (message_ports_.count(entangled_id)) {
+ message_ports_[entangled_id].entangled_message_port_id = MSG_ROUTING_NONE;
+ }
+ }
+ message_ports_.erase(erase_item);
+}
diff --git a/chrome/browser/worker_host/message_port_service.h b/chrome/browser/worker_host/message_port_service.h
new file mode 100644
index 0000000..9c30b6e
--- /dev/null
+++ b/chrome/browser/worker_host/message_port_service.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_SERVICE_H_
+#define CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_SERVICE_H_
+#pragma once
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/singleton.h"
+#include "base/string16.h"
+#include "base/task.h"
+#include "ipc/ipc_message.h"
+
+class WorkerMessageFilter;
+
+class MessagePortService {
+ public:
+ typedef std::vector<std::pair<string16, std::vector<int> > > QueuedMessages;
+
+ // Returns the MessagePortService singleton.
+ static MessagePortService* GetInstance();
+
+ // These methods correspond to the message port related IPCs.
+ void Create(int route_id, WorkerMessageFilter* filter, int* message_port_id);
+ void Destroy(int message_port_id);
+ void Entangle(int local_message_port_id, int remote_message_port_id);
+ void PostMessage(int sender_message_port_id,
+ const string16& message,
+ const std::vector<int>& sent_message_port_ids);
+ void QueueMessages(int message_port_id);
+ void SendQueuedMessages(int message_port_id,
+ const QueuedMessages& queued_messages);
+
+ // Updates the information needed to reach a message port when it's sent to a
+ // (possibly different) process.
+ void UpdateMessagePort(
+ int message_port_id,
+ WorkerMessageFilter* filter,
+ int routing_id);
+
+ void OnWorkerMessageFilterClosing(WorkerMessageFilter* filter);
+
+ // Attempts to send the queued messages for a message port.
+ void SendQueuedMessagesIfPossible(int message_port_id);
+
+ private:
+ friend struct DefaultSingletonTraits<MessagePortService>;
+
+ MessagePortService();
+ ~MessagePortService();
+
+ void PostMessageTo(int message_port_id,
+ const string16& message,
+ const std::vector<int>& sent_message_port_ids);
+
+ // Handles the details of removing a message port id. Before calling this,
+ // verify that the message port id exists.
+ void Erase(int message_port_id);
+
+ struct MessagePort;
+ typedef std::map<int, MessagePort> MessagePorts;
+ MessagePorts message_ports_;
+
+ // We need globally unique identifiers for each message port.
+ int next_message_port_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePortService);
+};
+
+#endif // CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_SERVICE_H_
diff --git a/chrome/browser/worker_host/worker_document_set.cc b/chrome/browser/worker_host/worker_document_set.cc
index 3588bb1..0b3c634 100644
--- a/chrome/browser/worker_host/worker_document_set.cc
+++ b/chrome/browser/worker_host/worker_document_set.cc
@@ -4,32 +4,34 @@
#include "chrome/browser/worker_host/worker_document_set.h"
+#include "base/logging.h"
+
WorkerDocumentSet::WorkerDocumentSet() {
}
-void WorkerDocumentSet::Add(IPC::Message::Sender* parent,
+void WorkerDocumentSet::Add(WorkerMessageFilter* parent,
unsigned long long document_id,
- int renderer_id,
- int render_view_route_id) {
- DocumentInfo info(parent, document_id, renderer_id, render_view_route_id);
+ int render_process_id,
+ int render_view_id) {
+ DocumentInfo info(parent, document_id, render_process_id, render_view_id);
document_set_.insert(info);
}
-bool WorkerDocumentSet::Contains(IPC::Message::Sender* parent,
+bool WorkerDocumentSet::Contains(WorkerMessageFilter* parent,
unsigned long long document_id) const {
for (DocumentInfoSet::const_iterator i = document_set_.begin();
i != document_set_.end(); ++i) {
- if (i->sender() == parent && i->document_id() == document_id)
+ if (i->filter() == parent && i->document_id() == document_id)
return true;
}
return false;
}
-void WorkerDocumentSet::Remove(IPC::Message::Sender* parent,
+void WorkerDocumentSet::Remove(WorkerMessageFilter* parent,
unsigned long long document_id) {
for (DocumentInfoSet::iterator i = document_set_.begin();
i != document_set_.end(); i++) {
- if (i->sender() == parent && i->document_id() == document_id) {
+ if (i->filter() == parent && i->document_id() == document_id) {
document_set_.erase(i);
break;
}
@@ -38,14 +40,14 @@ void WorkerDocumentSet::Remove(IPC::Message::Sender* parent,
DCHECK(!Contains(parent, document_id));
}
-void WorkerDocumentSet::RemoveAll(IPC::Message::Sender* parent) {
+void WorkerDocumentSet::RemoveAll(WorkerMessageFilter* parent) {
for (DocumentInfoSet::iterator i = document_set_.begin();
i != document_set_.end();) {
// Note this idiom is somewhat tricky - calling document_set_.erase(iter)
// invalidates any iterators that point to the element being removed, so
// bump the iterator beyond the item being removed before calling erase.
- if (i->sender() == parent) {
+ if (i->filter() == parent) {
DocumentInfoSet::iterator item_to_delete = i++;
document_set_.erase(item_to_delete);
} else {
@@ -55,12 +57,13 @@ void WorkerDocumentSet::RemoveAll(IPC::Message::Sender* parent) {
}
WorkerDocumentSet::DocumentInfo::DocumentInfo(
- IPC::Message::Sender* sender, unsigned long long document_id,
- int renderer_id, int render_view_route_id)
- : sender_(sender),
+ WorkerMessageFilter* filter, unsigned long long document_id,
+ int render_process_id, int render_view_id)
+ : filter_(filter),
document_id_(document_id),
- renderer_id_(renderer_id),
- render_view_route_id_(render_view_route_id) {
+ render_process_id_(render_process_id),
+ render_view_id_(render_view_id) {
}
-WorkerDocumentSet::~WorkerDocumentSet() {}
+WorkerDocumentSet::~WorkerDocumentSet() {
+}
diff --git a/chrome/browser/worker_host/worker_document_set.h b/chrome/browser/worker_host/worker_document_set.h
index 7894fc4..49da2b6 100644
--- a/chrome/browser/worker_host/worker_document_set.h
+++ b/chrome/browser/worker_host/worker_document_set.h
@@ -10,7 +10,8 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
-#include "ipc/ipc_message.h"
+
+class WorkerMessageFilter;
// The WorkerDocumentSet tracks all of the DOM documents associated with a
// set of workers. With nested workers, multiple workers can share the same
@@ -23,53 +24,53 @@ class WorkerDocumentSet : public base::RefCounted<WorkerDocumentSet> {
// The information we track for each document
class DocumentInfo {
public:
- DocumentInfo(IPC::Message::Sender* sender, unsigned long long document_id,
- int renderer_id, int render_view_route_id);
- IPC::Message::Sender* sender() const { return sender_; }
+ DocumentInfo(WorkerMessageFilter* filter, unsigned long long document_id,
+ int renderer_process_id, int render_view_id);
+ WorkerMessageFilter* filter() const { return filter_; }
unsigned long long document_id() const { return document_id_; }
- int renderer_id() const { return renderer_id_; }
- int render_view_route_id() const { return render_view_route_id_; }
+ int render_process_id() const { return render_process_id_; }
+ int render_view_id() const { return render_view_id_; }
// Define operator "<", which is used to determine uniqueness within
// the set.
bool operator <(const DocumentInfo& other) const {
// Items are identical if the sender and document_id are identical,
// otherwise create an arbitrary stable ordering based on the document
- // id/sender.
- if (sender() == other.sender()) {
+ // id/filter.
+ if (filter() == other.filter()) {
return document_id() < other.document_id();
} else {
- return reinterpret_cast<unsigned long long>(sender()) <
- reinterpret_cast<unsigned long long>(other.sender());
+ return reinterpret_cast<unsigned long long>(filter()) <
+ reinterpret_cast<unsigned long long>(other.filter());
}
}
private:
- IPC::Message::Sender* sender_;
+ WorkerMessageFilter* filter_;
unsigned long long document_id_;
- int renderer_id_;
- int render_view_route_id_;
+ int render_process_id_;
+ int render_view_id_;
};
// Adds a document to a shared worker's document set. Also includes the
- // associated renderer_id the document is associated with, to enable
+ // associated render_process_id the document is associated with, to enable
// communication with the parent tab for things like http auth dialogs.
- void Add(IPC::Message::Sender* parent,
+ void Add(WorkerMessageFilter* parent,
unsigned long long document_id,
- int renderer_id,
- int render_view_route_id);
+ int render_process_id,
+ int render_view_id);
// Checks to see if a document is in a shared worker's document set.
- bool Contains(IPC::Message::Sender* parent,
+ bool Contains(WorkerMessageFilter* parent,
unsigned long long document_id) const;
// Removes a specific document from a worker's document set when that document
// is detached.
- void Remove(IPC::Message::Sender* parent, unsigned long long document_id);
+ void Remove(WorkerMessageFilter* parent, unsigned long long document_id);
// Invoked when a render process exits, to remove all associated documents
// from a worker's document set.
- void RemoveAll(IPC::Message::Sender* parent);
+ void RemoveAll(WorkerMessageFilter* parent);
bool IsEmpty() const { return document_set_.empty(); }
diff --git a/chrome/browser/worker_host/worker_message_filter.cc b/chrome/browser/worker_host/worker_message_filter.cc
new file mode 100644
index 0000000..b598202
--- /dev/null
+++ b/chrome/browser/worker_host/worker_message_filter.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2010 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 "chrome/browser/worker_host/worker_message_filter.h"
+
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/worker_host/message_port_service.h"
+#include "chrome/browser/worker_host/worker_service.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+#include "chrome/common/worker_messages.h"
+
+WorkerMessageFilter::WorkerMessageFilter(
+ int render_process_id,
+ URLRequestContextGetter* request_context,
+ ResourceDispatcherHost* resource_dispatcher_host,
+ CallbackWithReturnValue<int>::Type* next_routing_id)
+ : render_process_id_(render_process_id),
+ request_context_(request_context),
+ resource_dispatcher_host_(resource_dispatcher_host),
+ next_routing_id_(next_routing_id) {
+}
+
+WorkerMessageFilter::~WorkerMessageFilter() {
+}
+
+void WorkerMessageFilter::OnChannelClosing() {
+ BrowserMessageFilter::OnChannelClosing();
+
+ MessagePortService::GetInstance()->OnWorkerMessageFilterClosing(this);
+ WorkerService::GetInstance()->OnWorkerMessageFilterClosing(this);
+}
+
+bool WorkerMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(WorkerMessageFilter, message, *message_was_ok)
+ // Worker messages.
+ // Only sent from renderer for now, until we have nested workers.
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWorker, OnCreateWorker)
+ // Only sent from renderer for now, until we have nested workers.
+ IPC_MESSAGE_HANDLER(ViewHostMsg_LookupSharedWorker, OnLookupSharedWorker)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker,
+ OnCancelCreateDedicatedWorker)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker, OnForwardToWorker)
+ // Only sent from renderer.
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentDetached, OnDocumentDetached)
+ // Message Port related messages.
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_CreateMessagePort,
+ OnCreateMessagePort)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_DestroyMessagePort,
+ MessagePortService::GetInstance(),
+ MessagePortService::Destroy)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_Entangle,
+ MessagePortService::GetInstance(),
+ MessagePortService::Entangle)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_PostMessage,
+ MessagePortService::GetInstance(),
+ MessagePortService::PostMessage)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_QueueMessages,
+ MessagePortService::GetInstance(),
+ MessagePortService::QueueMessages)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_SendQueuedMessages,
+ MessagePortService::GetInstance(),
+ MessagePortService::SendQueuedMessages)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP_EX()
+
+ return handled;
+}
+
+int WorkerMessageFilter::GetNextRoutingID() {
+ return next_routing_id_->Run();
+}
+
+void WorkerMessageFilter::OnCreateWorker(
+ const ViewHostMsg_CreateWorker_Params& params,
+ int* route_id) {
+ *route_id = params.route_id != MSG_ROUTING_NONE ?
+ params.route_id : next_routing_id_->Run();
+ WorkerService::GetInstance()->CreateWorker(
+ params, *route_id, this, request_context_);
+}
+
+void WorkerMessageFilter::OnLookupSharedWorker(
+ const ViewHostMsg_CreateWorker_Params& params,
+ bool* exists,
+ int* route_id,
+ bool* url_error) {
+ *route_id = next_routing_id_->Run();
+
+ bool off_the_record = static_cast<ChromeURLRequestContext*>(
+ request_context_->GetURLRequestContext())->is_off_the_record();
+ WorkerService::GetInstance()->LookupSharedWorker(
+ params, *route_id, this, off_the_record, exists, url_error);
+}
+
+void WorkerMessageFilter::OnCancelCreateDedicatedWorker(int route_id) {
+ WorkerService::GetInstance()->CancelCreateDedicatedWorker(route_id, this);
+}
+
+void WorkerMessageFilter::OnForwardToWorker(const IPC::Message& message) {
+ WorkerService::GetInstance()->ForwardToWorker(message, this);
+}
+
+void WorkerMessageFilter::OnDocumentDetached(unsigned long long document_id) {
+ WorkerService::GetInstance()->DocumentDetached(document_id, this);
+}
+
+void WorkerMessageFilter::OnCreateMessagePort(int *route_id,
+ int* message_port_id) {
+ *route_id = next_routing_id_->Run();
+ MessagePortService::GetInstance()->Create(*route_id, this, message_port_id);
+}
diff --git a/chrome/browser/worker_host/worker_message_filter.h b/chrome/browser/worker_host/worker_message_filter.h
new file mode 100644
index 0000000..2e32dab
--- /dev/null
+++ b/chrome/browser/worker_host/worker_message_filter.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_WORKER_HOST_WORKER_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_WORKER_HOST_WORKER_MESSAGE_FILTER_H_
+
+#include "base/callback.h"
+#include "chrome/browser/browser_message_filter.h"
+
+class ResourceDispatcherHost;
+class URLRequestContextGetter;
+struct ViewHostMsg_CreateWorker_Params;
+
+class WorkerMessageFilter : public BrowserMessageFilter {
+ public:
+ // |next_routing_id| is owned by this object. It can be used up until
+ // OnChannelClosing.
+ WorkerMessageFilter(
+ int render_process_id,
+ URLRequestContextGetter* request_context,
+ ResourceDispatcherHost* resource_dispatcher_host,
+ CallbackWithReturnValue<int>::Type* next_routing_id);
+
+ // BrowserMessageFilter implementation.
+ virtual void OnChannelClosing();
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
+ int GetNextRoutingID();
+ int render_process_id() const { return render_process_id_; }
+ ResourceDispatcherHost* resource_dispatcher_host() const {
+ return resource_dispatcher_host_;
+ }
+
+ private:
+ ~WorkerMessageFilter();
+
+ // Message handlers.
+ void OnCreateWorker(const ViewHostMsg_CreateWorker_Params& params,
+ int* route_id);
+ void OnLookupSharedWorker(const ViewHostMsg_CreateWorker_Params& params,
+ bool* exists,
+ int* route_id,
+ bool* url_error);
+ void OnCancelCreateDedicatedWorker(int route_id);
+ void OnForwardToWorker(const IPC::Message& message);
+ void OnDocumentDetached(unsigned long long document_id);
+ void OnCreateMessagePort(int* route_id, int* message_port_id);
+
+ int render_process_id_;
+ scoped_refptr<URLRequestContextGetter> request_context_;
+ ResourceDispatcherHost* resource_dispatcher_host_;
+
+ // This is guaranteed to be valid until OnChannelClosing is closed, and it's
+ // not used after.
+ scoped_ptr<CallbackWithReturnValue<int>::Type> next_routing_id_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(WorkerMessageFilter);
+};
+
+#endif // CHROME_BROWSER_WORKER_HOST_WORKER_MESSAGE_FILTER_H_
diff --git a/chrome/browser/worker_host/worker_process_host.cc b/chrome/browser/worker_host/worker_process_host.cc
index ec1eed1..2006e2f 100644
--- a/chrome/browser/worker_host/worker_process_host.cc
+++ b/chrome/browser/worker_host/worker_process_host.cc
@@ -15,23 +15,23 @@
#include "chrome/browser/appcache/appcache_dispatcher_host.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/file_system/file_system_dispatcher_host.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/mime_registry_dispatcher.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/mime_registry_message_filter.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/blob_dispatcher_host.h"
-#include "chrome/browser/renderer_host/database_dispatcher_host.h"
-#include "chrome/browser/renderer_host/file_utilities_dispatcher_host.h"
+#include "chrome/browser/renderer_host/blob_message_filter.h"
+#include "chrome/browser/renderer_host/database_message_filter.h"
+#include "chrome/browser/renderer_host/file_utilities_message_filter.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/browser/worker_host/message_port_dispatcher.h"
+#include "chrome/browser/renderer_host/socket_stream_dispatcher_host.h"
+#include "chrome/browser/worker_host/message_port_service.h"
+#include "chrome/browser/worker_host/worker_message_filter.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/debug_flags.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/result_codes.h"
@@ -41,6 +41,30 @@
#include "net/base/registry_controlled_domain.h"
#include "webkit/fileapi/file_system_path_manager.h"
+namespace {
+
+// Helper class that we pass to SocketStreamDispatcherHost so that it can find
+// the right URLRequestContext for a request.
+class URLRequestContextOverride
+ : public ResourceMessageFilter::URLRequestContextOverride {
+ public:
+ explicit URLRequestContextOverride(
+ URLRequestContext* url_request_context)
+ : url_request_context_(url_request_context) {
+ }
+ virtual ~URLRequestContextOverride() {}
+
+ virtual URLRequestContext* GetRequestContext(
+ uint32 request_id, ResourceType::Type resource_type) {
+ return url_request_context_;
+ }
+
+ private:
+ URLRequestContext* url_request_context_;
+};
+
+} // namespace
+
// Notifies RenderViewHost that one or more worker objects crashed.
class WorkerCrashTask : public Task {
public:
@@ -66,50 +90,12 @@ class WorkerCrashTask : public Task {
WorkerProcessHost::WorkerProcessHost(
ResourceDispatcherHost* resource_dispatcher_host,
- ChromeURLRequestContext *request_context)
+ URLRequestContextGetter* request_context)
: BrowserChildProcessHost(WORKER_PROCESS, resource_dispatcher_host),
- request_context_(request_context),
- appcache_dispatcher_host_(
- new AppCacheDispatcherHost(request_context)),
- ALLOW_THIS_IN_INITIALIZER_LIST(blob_dispatcher_host_(
- new BlobDispatcherHost(
- this->id(), request_context->blob_storage_context()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(file_system_dispatcher_host_(
- new FileSystemDispatcherHost(this, request_context))),
- ALLOW_THIS_IN_INITIALIZER_LIST(file_utilities_dispatcher_host_(
- new FileUtilitiesDispatcherHost(this, this->id()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(mime_registry_dispatcher_(
- new MimeRegistryDispatcher(this))) {
- next_route_id_callback_.reset(NewCallbackWithReturnValue(
- WorkerService::GetInstance(), &WorkerService::next_worker_route_id));
- db_dispatcher_host_ = new DatabaseDispatcherHost(
- request_context->database_tracker(), this,
- request_context_->host_content_settings_map());
- appcache_dispatcher_host_->Initialize(this);
+ request_context_(request_context) {
}
WorkerProcessHost::~WorkerProcessHost() {
- // Shut down the database dispatcher host.
- db_dispatcher_host_->Shutdown();
-
- // Shut down the blob dispatcher host.
- blob_dispatcher_host_->Shutdown();
-
- // Shut down the file system dispatcher host.
- file_system_dispatcher_host_->Shutdown();
-
- // Shut down the file utilities dispatcher host.
- file_utilities_dispatcher_host_->Shutdown();
-
- // Shut down the mime registry dispatcher host.
- mime_registry_dispatcher_->Shutdown();
-
- // Let interested observers know we are being deleted.
- NotificationService::current()->Notify(
- NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
- Source<WorkerProcessHost>(this),
- NotificationService::NoDetails());
-
// If we crashed, tell the RenderViewHosts.
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
const WorkerDocumentSet::DocumentInfoSet& parents =
@@ -118,15 +104,15 @@ WorkerProcessHost::~WorkerProcessHost() {
parents.begin(); parent_iter != parents.end(); ++parent_iter) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- new WorkerCrashTask(parent_iter->renderer_id(),
- parent_iter->render_view_route_id()));
+ new WorkerCrashTask(parent_iter->render_process_id(),
+ parent_iter->render_view_id()));
}
}
ChildProcessSecurityPolicy::GetInstance()->Remove(id());
}
-bool WorkerProcessHost::Init() {
+bool WorkerProcessHost::Init(int render_process_id) {
if (!CreateChannel())
return false;
@@ -200,7 +186,7 @@ bool WorkerProcessHost::Init() {
// requests them.
ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
id(),
- request_context_->browser_file_system_context()->
+ GetChromeURLRequestContext()->file_system_context()->
path_manager()->base_path(),
base::PLATFORM_FILE_OPEN |
base::PLATFORM_FILE_CREATE |
@@ -215,9 +201,38 @@ bool WorkerProcessHost::Init() {
base::PLATFORM_FILE_WRITE_ATTRIBUTES);
}
+ CreateMessageFilters(render_process_id);
+
return true;
}
+void WorkerProcessHost::CreateMessageFilters(int render_process_id) {
+ ChromeURLRequestContext* chrome_url_context = GetChromeURLRequestContext();
+
+ worker_message_filter_= new WorkerMessageFilter(
+ render_process_id,
+ request_context_,
+ resource_dispatcher_host(),
+ NewCallbackWithReturnValue(
+ WorkerService::GetInstance(), &WorkerService::next_worker_route_id));
+ AddFilter(worker_message_filter_);
+ AddFilter(new AppCacheDispatcherHost(chrome_url_context, id()));
+ AddFilter(new FileSystemDispatcherHost(chrome_url_context));
+ AddFilter(new FileUtilitiesMessageFilter(id()));
+ AddFilter(
+ new BlobMessageFilter(id(), chrome_url_context->blob_storage_context()));
+ AddFilter(new MimeRegistryMessageFilter());
+ AddFilter(new DatabaseMessageFilter(
+ chrome_url_context->database_tracker(),
+ chrome_url_context->host_content_settings_map()));
+
+ SocketStreamDispatcherHost* socket_stream_dispatcher_host =
+ new SocketStreamDispatcherHost();
+ socket_stream_dispatcher_host->set_url_request_context_override(
+ new URLRequestContextOverride(chrome_url_context));
+ AddFilter(socket_stream_dispatcher_host);
+}
+
void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
ChildProcessSecurityPolicy::GetInstance()->GrantRequestURL(
id(), instance.url());
@@ -236,22 +251,21 @@ void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
UpdateTitle();
- // Walk all pending senders and let them know the worker has been created
+ // Walk all pending filters and let them know the worker has been created
// (could be more than one in the case where we had to queue up worker
// creation because the worker process limit was reached).
- for (WorkerInstance::SenderList::const_iterator i =
- instance.senders().begin();
- i != instance.senders().end(); ++i) {
+ for (WorkerInstance::FilterList::const_iterator i =
+ instance.filters().begin();
+ i != instance.filters().end(); ++i) {
i->first->Send(new ViewMsg_WorkerCreated(i->second));
}
}
bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
- IPC::Message::Sender* sender) {
+ WorkerMessageFilter* filter) {
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (!i->closed() && i->HasSender(sender, message.routing_id())) {
- RelayMessage(
- message, this, i->worker_route_id(), next_route_id_callback_.get());
+ if (!i->closed() && i->HasFilter(filter, message.routing_id())) {
+ RelayMessage(message, worker_message_filter_, i->worker_route_id());
return true;
}
}
@@ -259,111 +273,94 @@ bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
return false;
}
-URLRequestContext* WorkerProcessHost::GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return request_context_;
-}
-
-// Sent to notify the browser process when a worker context invokes close(), so
-// no new connections are sent to shared workers.
-void WorkerProcessHost::OnWorkerContextClosed(int worker_route_id) {
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->worker_route_id() == worker_route_id) {
- // Set the closed flag - this will stop any further messages from
- // being sent to the worker (messages can still be sent from the worker,
- // for exception reporting, etc).
- i->set_closed(true);
- break;
- }
- }
+void WorkerProcessHost::OnProcessLaunched() {
}
-void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
+bool WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
bool msg_is_ok = true;
- bool handled =
- appcache_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- db_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- blob_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- file_system_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- file_utilities_dispatcher_host_->OnMessageReceived(message) ||
- mime_registry_dispatcher_->OnMessageReceived(message) ||
- MessagePortDispatcher::GetInstance()->OnMessageReceived(
- message, this, next_route_id_callback_.get(), &msg_is_ok);
-
- if (!handled) {
- handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWorker, OnCreateWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_LookupSharedWorker, OnLookupSharedWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker,
- OnCancelCreateDedicatedWorker)
- IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextClosed,
- OnWorkerContextClosed);
- IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker,
- OnForwardToWorker)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(WorkerProcessHostMsg_AllowDatabase,
- OnAllowDatabase)
- IPC_MESSAGE_UNHANDLED(handled = false)
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
+ IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextClosed,
+ OnWorkerContextClosed)
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowDatabase, OnAllowDatabase)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
- }
if (!msg_is_ok) {
NOTREACHED();
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_WPH"));
base::KillProcess(handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
}
if (handled)
- return;
+ return true;
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
if (i->worker_route_id() == message.routing_id()) {
if (!i->shared()) {
// Don't relay messages from shared workers (all communication is via
// the message port).
- WorkerInstance::SenderInfo info = i->GetSender();
- CallbackWithReturnValue<int>::Type* next_route_id =
- GetNextRouteIdCallback(info.first);
- RelayMessage(message, info.first, info.second, next_route_id);
+ WorkerInstance::FilterInfo info = i->GetFilter();
+ RelayMessage(message, info.first, info.second);
}
if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) {
instances_.erase(i);
UpdateTitle();
}
- break;
+ return true;
}
}
+ return false;
}
-void WorkerProcessHost::OnProcessLaunched() {
- db_dispatcher_host_->Init(handle());
- file_system_dispatcher_host_->Init(handle());
- file_utilities_dispatcher_host_->Init(handle());
+// Sent to notify the browser process when a worker context invokes close(), so
+// no new connections are sent to shared workers.
+void WorkerProcessHost::OnWorkerContextClosed(int worker_route_id) {
+ for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
+ if (i->worker_route_id() == worker_route_id) {
+ // Set the closed flag - this will stop any further messages from
+ // being sent to the worker (messages can still be sent from the worker,
+ // for exception reporting, etc).
+ i->set_closed(true);
+ break;
+ }
+ }
}
-CallbackWithReturnValue<int>::Type* WorkerProcessHost::GetNextRouteIdCallback(
- IPC::Message::Sender* sender) {
- // We don't keep callbacks for senders associated with workers, so figure out
- // what kind of sender this is, and cast it to the correct class to get the
- // callback.
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- if (static_cast<IPC::Message::Sender*>(worker) == sender)
- return worker->next_route_id_callback_.get();
- }
+void WorkerProcessHost::OnAllowDatabase(int worker_route_id,
+ const GURL& url,
+ const string16& name,
+ const string16& display_name,
+ unsigned long estimated_size,
+ bool* result) {
+ ContentSetting content_setting = GetChromeURLRequestContext()->
+ host_content_settings_map()->GetContentSetting(
+ url, CONTENT_SETTINGS_TYPE_COOKIES, "");
+
+ *result = content_setting != CONTENT_SETTING_BLOCK;
- // Must be a ResourceMessageFilter.
- return static_cast<ResourceMessageFilter*>(sender)->next_route_id_callback();
+ // Find the worker instance and forward the message to all attached documents.
+ for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
+ if (i->worker_route_id() != worker_route_id)
+ continue;
+ const WorkerDocumentSet::DocumentInfoSet& documents =
+ i->worker_document_set()->documents();
+ for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
+ documents.begin(); doc != documents.end(); ++doc) {
+ CallRenderViewHostContentSettingsDelegate(
+ doc->render_process_id(), doc->render_view_id(),
+ &RenderViewHostDelegate::ContentSettings::OnWebDatabaseAccessed,
+ url, name, display_name, estimated_size, !*result);
+ }
+ break;
+ }
}
void WorkerProcessHost::RelayMessage(
const IPC::Message& message,
- IPC::Message::Sender* sender,
- int route_id,
- CallbackWithReturnValue<int>::Type* next_route_id) {
-
+ WorkerMessageFilter* filter,
+ int route_id) {
if (message.type() == WorkerMsg_PostMessage::ID) {
// We want to send the receiver a routing id for the new channel, so
// crack the message first.
@@ -378,19 +375,19 @@ void WorkerProcessHost::RelayMessage(
return;
for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- new_routing_ids[i] = next_route_id->Run();
- MessagePortDispatcher::GetInstance()->UpdateMessagePort(
- sent_message_port_ids[i], sender, new_routing_ids[i], next_route_id);
+ new_routing_ids[i] = filter->GetNextRoutingID();
+ MessagePortService::GetInstance()->UpdateMessagePort(
+ sent_message_port_ids[i], filter, new_routing_ids[i]);
}
- sender->Send(new WorkerMsg_PostMessage(
+ filter->Send(new WorkerMsg_PostMessage(
route_id, msg, sent_message_port_ids, new_routing_ids));
// Send any queued messages to the sent message ports. We can only do this
// after sending the above message, since it's the one that sets up the
// message port route which the queued messages are sent to.
for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- MessagePortDispatcher::GetInstance()->
+ MessagePortService::GetInstance()->
SendQueuedMessagesIfPossible(sent_message_port_ids[i]);
}
} else if (message.type() == WorkerMsg_Connect::ID) {
@@ -401,35 +398,35 @@ void WorkerProcessHost::RelayMessage(
&message, &sent_message_port_id, &new_routing_id)) {
return;
}
- new_routing_id = next_route_id->Run();
- MessagePortDispatcher::GetInstance()->UpdateMessagePort(
- sent_message_port_id, sender, new_routing_id, next_route_id);
+ new_routing_id = filter->GetNextRoutingID();
+ MessagePortService::GetInstance()->UpdateMessagePort(
+ sent_message_port_id, filter, new_routing_id);
// Resend the message with the new routing id.
- sender->Send(new WorkerMsg_Connect(
+ filter->Send(new WorkerMsg_Connect(
route_id, sent_message_port_id, new_routing_id));
// Send any queued messages for the sent port.
- MessagePortDispatcher::GetInstance()->SendQueuedMessagesIfPossible(
+ MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
sent_message_port_id);
} else {
IPC::Message* new_message = new IPC::Message(message);
new_message->set_routing_id(route_id);
- sender->Send(new_message);
+ filter->Send(new_message);
return;
}
}
-void WorkerProcessHost::SenderShutdown(IPC::Message::Sender* sender) {
+void WorkerProcessHost::FilterShutdown(WorkerMessageFilter* filter) {
for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
bool shutdown = false;
- i->RemoveSenders(sender);
+ i->RemoveFilters(filter);
if (i->shared()) {
- i->worker_document_set()->RemoveAll(sender);
+ i->worker_document_set()->RemoveAll(filter);
if (i->worker_document_set()->IsEmpty()) {
shutdown = true;
}
- } else if (i->NumSenders() == 0) {
+ } else if (i->NumFilters() == 0) {
shutdown = true;
}
if (shutdown) {
@@ -441,6 +438,10 @@ void WorkerProcessHost::SenderShutdown(IPC::Message::Sender* sender) {
}
}
+bool WorkerProcessHost::CanShutdown() {
+ return instances_.empty();
+}
+
void WorkerProcessHost::UpdateTitle() {
std::set<std::string> titles;
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
@@ -452,8 +453,7 @@ void WorkerProcessHost::UpdateTitle() {
// Check if it's an extension-created worker, in which case we want to use
// the name of the extension.
- std::string extension_name = static_cast<ChromeURLRequestContext*>(
- Profile::GetDefaultRequestContext()->GetURLRequestContext())->
+ std::string extension_name = GetChromeURLRequestContext()->
extension_info_map()->GetNameForExtension(title);
if (!extension_name.empty()) {
titles.insert(extension_name);
@@ -477,96 +477,19 @@ void WorkerProcessHost::UpdateTitle() {
set_name(ASCIIToWide(display_title));
}
-void WorkerProcessHost::OnLookupSharedWorker(
- const ViewHostMsg_CreateWorker_Params& params,
- bool* exists,
- int* route_id,
- bool* url_mismatch) {
- *route_id = WorkerService::GetInstance()->next_worker_route_id();
- // TODO(atwilson): Add code to pass in the current worker's document set for
- // these nested workers. Code below will not work for SharedWorkers as it
- // only looks at a single parent.
- DCHECK(instances_.front().worker_document_set()->documents().size() == 1);
- WorkerDocumentSet::DocumentInfoSet::const_iterator first_parent =
- instances_.front().worker_document_set()->documents().begin();
- *exists = WorkerService::GetInstance()->LookupSharedWorker(
- params.url, params.name, instances_.front().off_the_record(),
- params.document_id, first_parent->renderer_id(),
- first_parent->render_view_route_id(), this, *route_id, url_mismatch);
-}
-
-void WorkerProcessHost::OnCreateWorker(
- const ViewHostMsg_CreateWorker_Params& params, int* route_id) {
- DCHECK(instances_.size() == 1); // Only called when one process per worker.
- // TODO(atwilson): Add code to pass in the current worker's document set for
- // these nested workers. Code below will not work for SharedWorkers as it
- // only looks at a single parent.
- DCHECK(instances_.front().worker_document_set()->documents().size() == 1);
- WorkerDocumentSet::DocumentInfoSet::const_iterator first_parent =
- instances_.front().worker_document_set()->documents().begin();
- *route_id = params.route_id == MSG_ROUTING_NONE ?
- WorkerService::GetInstance()->next_worker_route_id() : params.route_id;
-
- if (params.is_shared)
- WorkerService::GetInstance()->CreateSharedWorker(
- params.url, instances_.front().off_the_record(),
- params.name, params.document_id, first_parent->renderer_id(),
- first_parent->render_view_route_id(), this, *route_id,
- params.script_resource_appcache_id, request_context_);
- else
- WorkerService::GetInstance()->CreateDedicatedWorker(
- params.url, instances_.front().off_the_record(),
- params.document_id, first_parent->renderer_id(),
- first_parent->render_view_route_id(), this, *route_id,
- id(), params.parent_appcache_host_id, request_context_);
-}
-
-void WorkerProcessHost::OnCancelCreateDedicatedWorker(int route_id) {
- WorkerService::GetInstance()->CancelCreateDedicatedWorker(this, route_id);
-}
-
-void WorkerProcessHost::OnForwardToWorker(const IPC::Message& message) {
- WorkerService::GetInstance()->ForwardMessage(message, this);
-}
-
-void WorkerProcessHost::OnAllowDatabase(const GURL& url,
- const string16& name,
- const string16& display_name,
- unsigned long estimated_size,
- IPC::Message* reply_msg) {
- ContentSetting content_setting =
- request_context_->host_content_settings_map()->GetContentSetting(
- url, CONTENT_SETTINGS_TYPE_COOKIES, "");
-
- bool allowed = content_setting != CONTENT_SETTING_BLOCK;
-
- // Find the worker instance and forward the message to all attached documents.
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->worker_route_id() != reply_msg->routing_id())
- continue;
- const WorkerDocumentSet::DocumentInfoSet& documents =
- i->worker_document_set()->documents();
- for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
- documents.begin(); doc != documents.end(); ++doc) {
- CallRenderViewHostContentSettingsDelegate(
- doc->renderer_id(), doc->render_view_route_id(),
- &RenderViewHostDelegate::ContentSettings::OnWebDatabaseAccessed,
- url, name, display_name, estimated_size, !allowed);
- }
- break;
- }
- WorkerProcessHostMsg_AllowDatabase::WriteReplyParams(reply_msg, allowed);
- Send(reply_msg);
+ChromeURLRequestContext* WorkerProcessHost::GetChromeURLRequestContext() {
+ return static_cast<ChromeURLRequestContext*>(
+ request_context_->GetURLRequestContext());
}
-void WorkerProcessHost::DocumentDetached(IPC::Message::Sender* parent,
+void WorkerProcessHost::DocumentDetached(WorkerMessageFilter* filter,
unsigned long long document_id) {
// Walk all instances and remove the document from their document set.
for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
if (!i->shared()) {
++i;
} else {
- i->worker_document_set()->Remove(parent, document_id);
+ i->worker_document_set()->Remove(filter, document_id);
if (i->worker_document_set()->IsEmpty()) {
// This worker has no more associated documents - shut it down.
Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
@@ -587,7 +510,7 @@ WorkerProcessHost::WorkerInstance::WorkerInstance(
int parent_process_id,
int parent_appcache_host_id,
int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context)
+ URLRequestContextGetter* request_context)
: url_(url),
shared_(shared),
off_the_record_(off_the_record),
@@ -599,8 +522,6 @@ WorkerProcessHost::WorkerInstance::WorkerInstance(
main_resource_appcache_id_(main_resource_appcache_id),
request_context_(request_context),
worker_document_set_(new WorkerDocumentSet()) {
- DCHECK(!request_context ||
- (off_the_record == request_context->is_off_the_record()));
}
WorkerProcessHost::WorkerInstance::~WorkerInstance() {
@@ -631,65 +552,65 @@ bool WorkerProcessHost::WorkerInstance::Matches(
return name_ == match_name;
}
-void WorkerProcessHost::WorkerInstance::AddSender(IPC::Message::Sender* sender,
- int sender_route_id) {
- if (!HasSender(sender, sender_route_id)) {
- SenderInfo info(sender, sender_route_id);
- senders_.push_back(info);
+void WorkerProcessHost::WorkerInstance::AddFilter(WorkerMessageFilter* filter,
+ int route_id) {
+ if (!HasFilter(filter, route_id)) {
+ FilterInfo info(filter, route_id);
+ filters_.push_back(info);
}
- // Only shared workers can have more than one associated sender.
- DCHECK(shared_ || senders_.size() == 1);
+ // Only shared workers can have more than one associated filter.
+ DCHECK(shared_ || filters_.size() == 1);
}
-void WorkerProcessHost::WorkerInstance::RemoveSender(
- IPC::Message::Sender* sender, int sender_route_id) {
- for (SenderList::iterator i = senders_.begin(); i != senders_.end();) {
- if (i->first == sender && i->second == sender_route_id)
- i = senders_.erase(i);
+void WorkerProcessHost::WorkerInstance::RemoveFilter(
+ WorkerMessageFilter* filter, int route_id) {
+ for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
+ if (i->first == filter && i->second == route_id)
+ i = filters_.erase(i);
else
++i;
}
- // Should not be duplicate copies in the sender set.
- DCHECK(!HasSender(sender, sender_route_id));
+ // Should not be duplicate copies in the filter set.
+ DCHECK(!HasFilter(filter, route_id));
}
-void WorkerProcessHost::WorkerInstance::RemoveSenders(
- IPC::Message::Sender* sender) {
- for (SenderList::iterator i = senders_.begin(); i != senders_.end();) {
- if (i->first == sender)
- i = senders_.erase(i);
+void WorkerProcessHost::WorkerInstance::RemoveFilters(
+ WorkerMessageFilter* filter) {
+ for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
+ if (i->first == filter)
+ i = filters_.erase(i);
else
++i;
}
}
-bool WorkerProcessHost::WorkerInstance::HasSender(
- IPC::Message::Sender* sender, int sender_route_id) const {
- for (SenderList::const_iterator i = senders_.begin(); i != senders_.end();
+bool WorkerProcessHost::WorkerInstance::HasFilter(
+ WorkerMessageFilter* filter, int route_id) const {
+ for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
++i) {
- if (i->first == sender && i->second == sender_route_id)
+ if (i->first == filter && i->second == route_id)
return true;
}
return false;
}
bool WorkerProcessHost::WorkerInstance::RendererIsParent(
- int renderer_id, int render_view_route_id) const {
+ int render_process_id, int render_view_id) const {
const WorkerDocumentSet::DocumentInfoSet& parents =
worker_document_set()->documents();
for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
parents.begin();
parent_iter != parents.end(); ++parent_iter) {
- if (parent_iter->renderer_id() == renderer_id &&
- parent_iter->render_view_route_id() == render_view_route_id) {
+ if (parent_iter->render_process_id() == render_process_id &&
+ parent_iter->render_view_id() == render_view_id) {
return true;
}
}
return false;
}
-WorkerProcessHost::WorkerInstance::SenderInfo
-WorkerProcessHost::WorkerInstance::GetSender() const {
- DCHECK(NumSenders() == 1);
- return *senders_.begin();
+WorkerProcessHost::WorkerInstance::FilterInfo
+WorkerProcessHost::WorkerInstance::GetFilter() const {
+ DCHECK(NumFilters() == 1);
+ return *filters_.begin();
}
diff --git a/chrome/browser/worker_host/worker_process_host.h b/chrome/browser/worker_host/worker_process_host.h
index 2ddcdff..f3f6fdd 100644
--- a/chrome/browser/worker_host/worker_process_host.h
+++ b/chrome/browser/worker_host/worker_process_host.h
@@ -9,34 +9,19 @@
#include <list>
#include "base/basictypes.h"
-#include "base/callback.h"
#include "base/file_path.h"
-#include "base/ref_counted.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/worker_host/worker_document_set.h"
#include "googleurl/src/gurl.h"
-#include "ipc/ipc_channel.h"
-
-class AppCacheDispatcherHost;
-class BlobDispatcherHost;
-class ChromeURLRequestContext;
-class ChromeURLRequestContextGetter;
-class DatabaseDispatcherHost;
-class FileSystemDispatcherHost;
-class FileUtilitiesDispatcherHost;
-class MimeRegistryDispatcher;
-namespace webkit_database {
-class DatabaseTracker;
-} // namespace webkit_database
-
-struct ViewHostMsg_CreateWorker_Params;
+
+class URLRequestContextGetter;
// The WorkerProcessHost is the interface that represents the browser side of
// the browser <-> worker communication channel. There will be one
// WorkerProcessHost per worker process. Currently each worker runs in its own
// process, but that may change. However, we do assume [by storing a
-// ChromeURLRequestContext] that a WorkerProcessHost serves a single Profile.
+// URLRequestContext] that a WorkerProcessHost serves a single Profile.
class WorkerProcessHost : public BrowserChildProcessHost {
public:
@@ -52,24 +37,24 @@ class WorkerProcessHost : public BrowserChildProcessHost {
int parent_process_id,
int parent_appcache_host_id,
int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context);
+ URLRequestContextGetter* request_context);
~WorkerInstance();
// Unique identifier for a worker client.
- typedef std::pair<IPC::Message::Sender*, int> SenderInfo;
+ typedef std::pair<WorkerMessageFilter*, int> FilterInfo;
- // APIs to manage the sender list for a given instance.
- void AddSender(IPC::Message::Sender* sender, int sender_route_id);
- void RemoveSender(IPC::Message::Sender* sender, int sender_route_id);
- void RemoveSenders(IPC::Message::Sender* sender);
- bool HasSender(IPC::Message::Sender* sender, int sender_route_id) const;
- bool RendererIsParent(int renderer_id, int render_view_route_id) const;
- int NumSenders() const { return senders_.size(); }
- // Returns the single sender (must only be one).
- SenderInfo GetSender() const;
+ // APIs to manage the filter list for a given instance.
+ void AddFilter(WorkerMessageFilter* filter, int route_id);
+ void RemoveFilter(WorkerMessageFilter* filter, int route_id);
+ void RemoveFilters(WorkerMessageFilter* filter);
+ bool HasFilter(WorkerMessageFilter* filter, int route_id) const;
+ bool RendererIsParent(int render_process_id, int render_view_id) const;
+ int NumFilters() const { return filters_.size(); }
+ // Returns the single filter (must only be one).
+ FilterInfo GetFilter() const;
- typedef std::list<SenderInfo> SenderList;
- const SenderList& senders() const { return senders_; }
+ typedef std::list<FilterInfo> FilterList;
+ const FilterList& filters() const { return filters_; }
// Checks if this WorkerInstance matches the passed url/name params
// (per the comparison algorithm in the WebWorkers spec). This API only
@@ -100,12 +85,12 @@ class WorkerProcessHost : public BrowserChildProcessHost {
WorkerDocumentSet* worker_document_set() const {
return worker_document_set_;
}
- ChromeURLRequestContext* request_context() const {
+ URLRequestContextGetter* request_context() const {
return request_context_;
}
private:
- // Set of all senders (clients) associated with this worker.
+ // Set of all filters (clients) associated with this worker.
GURL url_;
bool shared_;
bool off_the_record_;
@@ -115,34 +100,36 @@ class WorkerProcessHost : public BrowserChildProcessHost {
int parent_process_id_;
int parent_appcache_host_id_;
int64 main_resource_appcache_id_;
- scoped_refptr<ChromeURLRequestContext> request_context_;
- SenderList senders_;
+ scoped_refptr<URLRequestContextGetter> request_context_;
+ FilterList filters_;
scoped_refptr<WorkerDocumentSet> worker_document_set_;
};
WorkerProcessHost(
ResourceDispatcherHost* resource_dispatcher_host,
- ChromeURLRequestContext* request_context);
+ URLRequestContextGetter* request_context);
~WorkerProcessHost();
// Starts the process. Returns true iff it succeeded.
- bool Init();
+ // |render_process_id| is the renderer process responsible for starting this
+ // worker.
+ bool Init(int render_process_id);
// Creates a worker object in the process.
void CreateWorker(const WorkerInstance& instance);
// Returns true iff the given message from a renderer process was forwarded to
// the worker.
- bool FilterMessage(const IPC::Message& message, IPC::Message::Sender* sender);
+ bool FilterMessage(const IPC::Message& message, WorkerMessageFilter* filter);
- void SenderShutdown(IPC::Message::Sender* sender);
+ void FilterShutdown(WorkerMessageFilter* filter);
// Shuts down any shared workers that are no longer referenced by active
// documents.
- void DocumentDetached(IPC::Message::Sender* sender,
+ void DocumentDetached(WorkerMessageFilter* filter,
unsigned long long document_id);
- ChromeURLRequestContext* request_context() const {
+ URLRequestContextGetter* request_context() const {
return request_context_;
}
@@ -154,68 +141,45 @@ class WorkerProcessHost : public BrowserChildProcessHost {
Instances& mutable_instances() { return instances_; }
private:
- // ResourceDispatcherHost::Receiver implementation:
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data);
-
- // Called when a message arrives from the worker process.
- virtual void OnMessageReceived(const IPC::Message& message);
-
// Called when the process has been launched successfully.
virtual void OnProcessLaunched();
- // Called when the app invokes close() from within worker context.
- void OnWorkerContextClosed(int worker_route_id);
+ // Creates and adds the message filters.
+ void CreateMessageFilters(int render_process_id);
- // Called if a worker tries to connect to a shared worker.
- void OnLookupSharedWorker(const ViewHostMsg_CreateWorker_Params& params,
- bool* exists,
- int* route_id,
- bool* url_error);
+ // IPC::Channel::Listener implementation:
+ // Called when a message arrives from the worker process.
+ virtual bool OnMessageReceived(const IPC::Message& message);
- // Given a Sender, returns the callback that generates a new routing id.
- static CallbackWithReturnValue<int>::Type* GetNextRouteIdCallback(
- IPC::Message::Sender* sender);
+ void OnWorkerContextClosed(int worker_route_id);
+ void OnAllowDatabase(int worker_route_id,
+ const GURL& url,
+ const string16& name,
+ const string16& display_name,
+ unsigned long estimated_size,
+ bool* result);
// Relays a message to the given endpoint. Takes care of parsing the message
// if it contains a message port and sending it a valid route id.
static void RelayMessage(const IPC::Message& message,
- IPC::Message::Sender* sender,
- int route_id,
- CallbackWithReturnValue<int>::Type* next_route_id);
+ WorkerMessageFilter* filter,
+ int route_id);
- virtual bool CanShutdown() { return instances_.empty(); }
+ virtual bool CanShutdown();
// Updates the title shown in the task manager.
void UpdateTitle();
- void OnCreateWorker(const ViewHostMsg_CreateWorker_Params& params,
- int* route_id);
- void OnCancelCreateDedicatedWorker(int route_id);
- void OnForwardToWorker(const IPC::Message& message);
-
- // Checks the content settings whether access to web databases is enabled and
- // relays the WebDatabaseAccessed message to all documents attached to a
- // worker.
- void OnAllowDatabase(const GURL& url,
- const string16& name,
- const string16& display_name,
- unsigned long estimated_size,
- IPC::Message* reply_msg);
+ ChromeURLRequestContext* GetChromeURLRequestContext();
Instances instances_;
- scoped_refptr<ChromeURLRequestContext> request_context_;
- scoped_ptr<AppCacheDispatcherHost> appcache_dispatcher_host_;
- scoped_refptr<DatabaseDispatcherHost> db_dispatcher_host_;
- scoped_ptr<BlobDispatcherHost> blob_dispatcher_host_;
- scoped_refptr<FileSystemDispatcherHost> file_system_dispatcher_host_;
- scoped_refptr<FileUtilitiesDispatcherHost> file_utilities_dispatcher_host_;
- scoped_refptr<MimeRegistryDispatcher> mime_registry_dispatcher_;
+ scoped_refptr<URLRequestContextGetter> request_context_;
- // A callback to create a routing id for the associated worker process.
- scoped_ptr<CallbackWithReturnValue<int>::Type> next_route_id_callback_;
+ // A reference to the filter associated with this worker process. We need to
+ // keep this around since we'll use it when forward messages to the worker
+ // process.
+ scoped_refptr<WorkerMessageFilter> worker_message_filter_;
DISALLOW_COPY_AND_ASSIGN(WorkerProcessHost);
};
diff --git a/chrome/browser/worker_host/worker_service.cc b/chrome/browser/worker_host/worker_service.cc
index 60fa03d..cea298d 100644
--- a/chrome/browser/worker_host/worker_service.cc
+++ b/chrome/browser/worker_host/worker_service.cc
@@ -4,19 +4,18 @@
#include "chrome/browser/worker_host/worker_service.h"
+#include <string>
+
#include "base/command_line.h"
#include "base/singleton.h"
#include "base/sys_info.h"
#include "base/thread.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/worker_host/worker_message_filter.h"
#include "chrome/browser/worker_host/worker_process_host.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/worker_messages.h"
#include "net/base/registry_controlled_domain.h"
@@ -28,97 +27,205 @@ WorkerService* WorkerService::GetInstance() {
return Singleton<WorkerService>::get();
}
-WorkerService::WorkerService()
- : next_worker_route_id_(0),
- resource_dispatcher_host_(NULL) {
- // Receive a notification if a message filter or WorkerProcessHost is deleted.
- registrar_.Add(this, NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
- NotificationService::AllSources());
-
- registrar_.Add(this, NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
- NotificationService::AllSources());
-}
-
-void WorkerService::Initialize(ResourceDispatcherHost* rdh) {
- resource_dispatcher_host_ = rdh;
+WorkerService::WorkerService() : next_worker_route_id_(0) {
}
WorkerService::~WorkerService() {
}
-bool WorkerService::CreateDedicatedWorker(
- const GURL& url,
- bool is_off_the_record,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int parent_process_id,
- int parent_appcache_host_id,
- ChromeURLRequestContext* request_context) {
- return CreateWorker(url, false, is_off_the_record, string16(),
- document_id, renderer_pid, render_view_route_id,
- sender, sender_route_id,
- parent_process_id, parent_appcache_host_id, 0,
- request_context);
-}
+void WorkerService::OnWorkerMessageFilterClosing(WorkerMessageFilter* filter) {
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ worker->FilterShutdown(filter);
+ }
+
+ // See if that process had any queued workers.
+ for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
+ i != queued_workers_.end();) {
+ i->RemoveFilters(filter);
+ if (i->NumFilters() == 0) {
+ i = queued_workers_.erase(i);
+ } else {
+ ++i;
+ }
+ }
-bool WorkerService::CreateSharedWorker(
- const GURL& url,
- bool is_off_the_record,
- const string16& name,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context) {
- return CreateWorker(url, true, is_off_the_record, name,
- document_id, renderer_pid, render_view_route_id,
- sender, sender_route_id,
- 0, 0, main_resource_appcache_id,
- request_context);
+ // Also, see if that process had any pending shared workers.
+ for (WorkerProcessHost::Instances::iterator iter =
+ pending_shared_workers_.begin();
+ iter != pending_shared_workers_.end(); ) {
+ iter->worker_document_set()->RemoveAll(filter);
+ if (iter->worker_document_set()->IsEmpty()) {
+ iter = pending_shared_workers_.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+
+ // Either a worker proceess has shut down, in which case we can start one of
+ // the queued workers, or a renderer has shut down, in which case it doesn't
+ // affect anything. We call this function in both scenarios because then we
+ // don't have to keep track which filters are from worker processes.
+ TryStartingQueuedWorker();
}
-bool WorkerService::CreateWorker(
- const GURL& url,
- bool is_shared,
- bool off_the_record,
- const string16& name,
- unsigned long long document_id,
- int renderer_id,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int parent_process_id,
- int parent_appcache_host_id,
- int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context) {
+void WorkerService::CreateWorker(const ViewHostMsg_CreateWorker_Params& params,
+ int route_id,
+ WorkerMessageFilter* filter,
+ URLRequestContextGetter* request_context) {
+
+ ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(
+ request_context->GetURLRequestContext());
+
// Generate a unique route id for the browser-worker communication that's
// unique among all worker processes. That way when the worker process sends
// a wrapped IPC message through us, we know which WorkerProcessHost to give
// it to.
- WorkerProcessHost::WorkerInstance instance(url,
- is_shared,
- off_the_record,
- name,
- next_worker_route_id(),
- parent_process_id,
- parent_appcache_host_id,
- main_resource_appcache_id,
- request_context);
- instance.AddSender(sender, sender_route_id);
+ WorkerProcessHost::WorkerInstance instance(
+ params.url,
+ params.is_shared,
+ context->is_off_the_record(),
+ params.name,
+ next_worker_route_id(),
+ params.is_shared ? 0 : filter->render_process_id(),
+ params.is_shared ? 0 : params.parent_appcache_host_id,
+ params.is_shared ? params.script_resource_appcache_id : 0,
+ request_context);
+ instance.AddFilter(filter, route_id);
instance.worker_document_set()->Add(
- sender, document_id, renderer_id, render_view_route_id);
+ filter, params.document_id, filter->render_process_id(),
+ params.render_view_route_id);
- return CreateWorkerFromInstance(instance);
+ CreateWorkerFromInstance(instance);
+}
+
+void WorkerService::LookupSharedWorker(
+ const ViewHostMsg_CreateWorker_Params& params,
+ int route_id,
+ WorkerMessageFilter* filter,
+ bool off_the_record,
+ bool* exists,
+ bool* url_mismatch) {
+
+ *exists = true;
+ WorkerProcessHost::WorkerInstance* instance = FindSharedWorkerInstance(
+ params.url, params.name, off_the_record);
+
+ if (!instance) {
+ // If no worker instance currently exists, we need to create a pending
+ // instance - this is to make sure that any subsequent lookups passing a
+ // mismatched URL get the appropriate url_mismatch error at lookup time.
+ // Having named shared workers was a Really Bad Idea due to details like
+ // this.
+ instance = CreatePendingInstance(params.url, params.name, off_the_record);
+ *exists = false;
+ }
+
+ // Make sure the passed-in instance matches the URL - if not, return an
+ // error.
+ if (params.url != instance->url()) {
+ *url_mismatch = true;
+ *exists = false;
+ } else {
+ *url_mismatch = false;
+ // Add our route ID to the existing instance so we can send messages to it.
+ instance->AddFilter(filter, route_id);
+
+ // Add the passed filter/document_id to the worker instance.
+ // TODO(atwilson): This won't work if the message is from a worker process.
+ // We don't support that yet though (this message is only sent from
+ // renderers) but when we do, we'll need to add code to pass in the current
+ // worker's document set for nested workers.
+ instance->worker_document_set()->Add(
+ filter, params.document_id, filter->render_process_id(),
+ params.render_view_route_id);
+ }
+}
+
+void WorkerService::CancelCreateDedicatedWorker(
+ int route_id,
+ WorkerMessageFilter* filter) {
+ for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
+ i != queued_workers_.end(); ++i) {
+ if (i->HasFilter(filter, route_id)) {
+ DCHECK(!i->shared());
+ queued_workers_.erase(i);
+ return;
+ }
+ }
+
+ // There could be a race condition where the WebWorkerProxy told us to cancel
+ // the worker right as we sent it a message say it's been created. Look at
+ // the running workers.
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ for (WorkerProcessHost::Instances::const_iterator instance =
+ worker->instances().begin();
+ instance != worker->instances().end(); ++instance) {
+ if (instance->HasFilter(filter, route_id)) {
+ // Fake a worker destroyed message so that WorkerProcessHost cleans up
+ // properly.
+ WorkerHostMsg_WorkerContextDestroyed message(route_id);
+ ForwardToWorker(message, filter);
+ return;
+ }
+ }
+ }
+
+ DCHECK(false) << "Couldn't find worker to cancel";
+}
+
+void WorkerService::ForwardToWorker(const IPC::Message& message,
+ WorkerMessageFilter* filter) {
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ if (worker->FilterMessage(message, filter))
+ return;
+ }
+
+ // TODO(jabdelmalek): tell filter that callee is gone
+}
+
+void WorkerService::DocumentDetached(unsigned long long document_id,
+ WorkerMessageFilter* filter) {
+ // Any associated shared workers can be shut down.
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ worker->DocumentDetached(filter, document_id);
+ }
+
+ // Remove any queued shared workers for this document.
+ for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
+ iter != queued_workers_.end();) {
+ if (iter->shared()) {
+ iter->worker_document_set()->Remove(filter, document_id);
+ if (iter->worker_document_set()->IsEmpty()) {
+ iter = queued_workers_.erase(iter);
+ continue;
+ }
+ }
+ ++iter;
+ }
+
+ // Remove the document from any pending shared workers.
+ for (WorkerProcessHost::Instances::iterator iter =
+ pending_shared_workers_.begin();
+ iter != pending_shared_workers_.end(); ) {
+ iter->worker_document_set()->Remove(filter, document_id);
+ if (iter->worker_document_set()->IsEmpty()) {
+ iter = pending_shared_workers_.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
}
bool WorkerService::CreateWorkerFromInstance(
WorkerProcessHost::WorkerInstance instance) {
-
// TODO(michaeln): We need to ensure that a process is working
// on behalf of a single profile. The process sharing logic below
// does not ensure that. Consider making WorkerService a per profile
@@ -144,17 +251,17 @@ bool WorkerService::CreateWorkerFromInstance(
WorkerProcessHost::WorkerInstance* existing_instance =
FindSharedWorkerInstance(
instance.url(), instance.name(), instance.off_the_record());
- WorkerProcessHost::WorkerInstance::SenderInfo sender_info =
- instance.GetSender();
+ WorkerProcessHost::WorkerInstance::FilterInfo filter_info =
+ instance.GetFilter();
// If this worker is already running, no need to create a new copy. Just
// inform the caller that the worker has been created.
if (existing_instance) {
- // Walk the worker's sender list to see if this client is listed. If not,
+ // Walk the worker's filter list to see if this client is listed. If not,
// then it means that the worker started by the client already exited so
// we should not attach to this new one (http://crbug.com/29243).
- if (!existing_instance->HasSender(sender_info.first, sender_info.second))
+ if (!existing_instance->HasFilter(filter_info.first, filter_info.second))
return false;
- sender_info.first->Send(new ViewMsg_WorkerCreated(sender_info.second));
+ filter_info.first->Send(new ViewMsg_WorkerCreated(filter_info.second));
return true;
}
@@ -162,38 +269,38 @@ bool WorkerService::CreateWorkerFromInstance(
WorkerProcessHost::WorkerInstance* pending = FindPendingInstance(
instance.url(), instance.name(), instance.off_the_record());
// If there's no instance *and* no pending instance (or there is a pending
- // instance but it does not contain our sender info), then it means the
+ // instance but it does not contain our filter info), then it means the
// worker started up and exited already. Log a warning because this should
// be a very rare occurrence and is probably a bug, but it *can* happen so
// handle it gracefully.
if (!pending ||
- !pending->HasSender(sender_info.first, sender_info.second)) {
+ !pending->HasFilter(filter_info.first, filter_info.second)) {
DLOG(WARNING) << "Pending worker already exited";
return false;
}
- // Assign the accumulated document set and sender list for this pending
+ // Assign the accumulated document set and filter list for this pending
// worker to the new instance.
DCHECK(!pending->worker_document_set()->IsEmpty());
instance.ShareDocumentSet(*pending);
- for (WorkerProcessHost::WorkerInstance::SenderList::const_iterator i =
- pending->senders().begin();
- i != pending->senders().end(); ++i) {
- instance.AddSender(i->first, i->second);
+ for (WorkerProcessHost::WorkerInstance::FilterList::const_iterator i =
+ pending->filters().begin();
+ i != pending->filters().end(); ++i) {
+ instance.AddFilter(i->first, i->second);
}
RemovePendingInstances(
instance.url(), instance.name(), instance.off_the_record());
- // Remove any queued instances of this worker and copy over the sender to
+ // Remove any queued instances of this worker and copy over the filter to
// this instance.
for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
iter != queued_workers_.end();) {
if (iter->Matches(instance.url(), instance.name(),
instance.off_the_record())) {
- DCHECK(iter->NumSenders() == 1);
- WorkerProcessHost::WorkerInstance::SenderInfo sender_info =
- iter->GetSender();
- instance.AddSender(sender_info.first, sender_info.second);
+ DCHECK(iter->NumFilters() == 1);
+ WorkerProcessHost::WorkerInstance::FilterInfo filter_info =
+ iter->GetFilter();
+ instance.AddFilter(filter_info.first, filter_info.second);
iter = queued_workers_.erase(iter);
} else {
++iter;
@@ -202,9 +309,15 @@ bool WorkerService::CreateWorkerFromInstance(
}
if (!worker) {
- worker = new WorkerProcessHost(resource_dispatcher_host_,
- instance.request_context());
- if (!worker->Init()) {
+ WorkerMessageFilter* first_filter = instance.filters().begin()->first;
+ worker = new WorkerProcessHost(
+ first_filter->resource_dispatcher_host(),
+ instance.request_context());
+ // TODO(atwilson): This won't work if the message is from a worker process.
+ // We don't support that yet though (this message is only sent from
+ // renderers) but when we do, we'll need to add code to pass in the current
+ // worker's document set for nested workers.
+ if (!worker->Init(first_filter->render_process_id())) {
delete worker;
return false;
}
@@ -218,128 +331,6 @@ bool WorkerService::CreateWorkerFromInstance(
return true;
}
-bool WorkerService::LookupSharedWorker(
- const GURL &url,
- const string16& name,
- bool off_the_record,
- unsigned long long document_id,
- int renderer_id,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- bool* url_mismatch) {
- bool found_instance = true;
- WorkerProcessHost::WorkerInstance* instance =
- FindSharedWorkerInstance(url, name, off_the_record);
-
- if (!instance) {
- // If no worker instance currently exists, we need to create a pending
- // instance - this is to make sure that any subsequent lookups passing a
- // mismatched URL get the appropriate url_mismatch error at lookup time.
- // Having named shared workers was a Really Bad Idea due to details like
- // this.
- instance = CreatePendingInstance(url, name, off_the_record);
- found_instance = false;
- }
-
- // Make sure the passed-in instance matches the URL - if not, return an
- // error.
- if (url != instance->url()) {
- *url_mismatch = true;
- return false;
- } else {
- *url_mismatch = false;
- }
-
- // Add our route ID to the existing instance so we can send messages to it.
- instance->AddSender(sender, sender_route_id);
-
- // Add the passed sender/document_id to the worker instance.
- instance->worker_document_set()->Add(
- sender, document_id, renderer_id, render_view_route_id);
- return found_instance;
-}
-
-void WorkerService::DocumentDetached(IPC::Message::Sender* sender,
- unsigned long long document_id) {
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- worker->DocumentDetached(sender, document_id);
- }
-
- // Remove any queued shared workers for this document.
- for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
- iter != queued_workers_.end();) {
- if (iter->shared()) {
- iter->worker_document_set()->Remove(sender, document_id);
- if (iter->worker_document_set()->IsEmpty()) {
- iter = queued_workers_.erase(iter);
- continue;
- }
- }
- ++iter;
- }
-
- // Remove the document from any pending shared workers.
- for (WorkerProcessHost::Instances::iterator iter =
- pending_shared_workers_.begin();
- iter != pending_shared_workers_.end(); ) {
- iter->worker_document_set()->Remove(sender, document_id);
- if (iter->worker_document_set()->IsEmpty()) {
- iter = pending_shared_workers_.erase(iter);
- } else {
- ++iter;
- }
- }
-
-}
-
-void WorkerService::CancelCreateDedicatedWorker(IPC::Message::Sender* sender,
- int sender_route_id) {
- for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
- i != queued_workers_.end(); ++i) {
- if (i->HasSender(sender, sender_route_id)) {
- DCHECK(!i->shared());
- queued_workers_.erase(i);
- return;
- }
- }
-
- // There could be a race condition where the WebWorkerProxy told us to cancel
- // the worker right as we sent it a message say it's been created. Look at
- // the running workers.
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- for (WorkerProcessHost::Instances::const_iterator instance =
- worker->instances().begin();
- instance != worker->instances().end(); ++instance) {
- if (instance->HasSender(sender, sender_route_id)) {
- // Fake a worker destroyed message so that WorkerProcessHost cleans up
- // properly.
- WorkerHostMsg_WorkerContextDestroyed msg(sender_route_id);
- ForwardMessage(msg, sender);
- return;
- }
- }
- }
-
- DCHECK(false) << "Couldn't find worker to cancel";
-}
-
-void WorkerService::ForwardMessage(const IPC::Message& message,
- IPC::Message::Sender* sender) {
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- if (worker->FilterMessage(message, sender))
- return;
- }
-
- // TODO(jabdelmalek): tell sender that callee is gone
-}
-
WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) {
int num_processes = 0;
std::string domain =
@@ -398,8 +389,8 @@ bool WorkerService::CanCreateWorkerProcess(
parents.begin();
parent_iter != parents.end(); ++parent_iter) {
bool hit_total_worker_limit = false;
- if (TabCanCreateWorkerProcess(parent_iter->renderer_id(),
- parent_iter->render_view_route_id(),
+ if (TabCanCreateWorkerProcess(parent_iter->render_process_id(),
+ parent_iter->render_view_id(),
&hit_total_worker_limit)) {
return true;
}
@@ -413,8 +404,8 @@ bool WorkerService::CanCreateWorkerProcess(
return false;
}
-bool WorkerService::TabCanCreateWorkerProcess(int renderer_id,
- int render_view_route_id,
+bool WorkerService::TabCanCreateWorkerProcess(int render_process_id,
+ int render_view_id,
bool* hit_total_worker_limit) {
int total_workers = 0;
int workers_per_tab = 0;
@@ -430,7 +421,7 @@ bool WorkerService::TabCanCreateWorkerProcess(int renderer_id,
*hit_total_worker_limit = true;
return false;
}
- if (cur_instance->RendererIsParent(renderer_id, render_view_route_id)) {
+ if (cur_instance->RendererIsParent(render_process_id, render_view_id)) {
workers_per_tab++;
if (workers_per_tab >= kMaxWorkersPerTabWhenSeparate)
return false;
@@ -441,53 +432,7 @@ bool WorkerService::TabCanCreateWorkerProcess(int renderer_id,
return true;
}
-void WorkerService::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN) {
- ResourceMessageFilter* sender = Source<ResourceMessageFilter>(source).ptr();
- SenderShutdown(sender);
- } else if (type.value == NotificationType::WORKER_PROCESS_HOST_SHUTDOWN) {
- WorkerProcessHost* sender = Source<WorkerProcessHost>(source).ptr();
- SenderShutdown(sender);
- WorkerProcessDestroyed(sender);
- } else {
- NOTREACHED();
- }
-}
-
-void WorkerService::SenderShutdown(IPC::Message::Sender* sender) {
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- worker->SenderShutdown(sender);
- }
-
- // See if that render process had any queued workers.
- for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
- i != queued_workers_.end();) {
- i->RemoveSenders(sender);
- if (i->NumSenders() == 0) {
- i = queued_workers_.erase(i);
- } else {
- ++i;
- }
- }
-
- // Also, see if that render process had any pending shared workers.
- for (WorkerProcessHost::Instances::iterator iter =
- pending_shared_workers_.begin();
- iter != pending_shared_workers_.end(); ) {
- iter->worker_document_set()->RemoveAll(sender);
- if (iter->worker_document_set()->IsEmpty()) {
- iter = pending_shared_workers_.erase(iter);
- } else {
- ++iter;
- }
- }
-}
-
-void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) {
+void WorkerService::TryStartingQueuedWorker() {
if (queued_workers_.empty())
return;
@@ -510,6 +455,30 @@ void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) {
}
}
+bool WorkerService::GetRendererForWorker(int worker_process_id,
+ int* render_process_id,
+ int* render_view_id) const {
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ if (iter->id() != worker_process_id)
+ continue;
+
+ // This code assumes one worker per process, see function comment in header!
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ WorkerProcessHost::Instances::const_iterator first_instance =
+ worker->instances().begin();
+ if (first_instance == worker->instances().end())
+ return false;
+
+ WorkerDocumentSet::DocumentInfoSet::const_iterator info =
+ first_instance->worker_document_set()->documents().begin();
+ *render_process_id = info->render_process_id();
+ *render_view_id = info->render_view_id();
+ return true;
+ }
+ return false;
+}
+
const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance(
int worker_process_id) {
for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
diff --git a/chrome/browser/worker_host/worker_service.h b/chrome/browser/worker_host/worker_service.h
index 744f116..7c39d57 100644
--- a/chrome/browser/worker_host/worker_service.h
+++ b/chrome/browser/worker_host/worker_service.h
@@ -11,83 +11,50 @@
#include "base/basictypes.h"
#include "base/singleton.h"
#include "chrome/browser/worker_host/worker_process_host.h"
-#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message.h"
-class ChromeURLRequestContext;
-class ResourceDispatcherHost;
+class URLRequestContextGetter;
+struct ViewHostMsg_CreateWorker_Params;
-class WorkerService : public NotificationObserver {
+// A singelton for managing HTML5 web workers.
+class WorkerService {
public:
// Returns the WorkerService singleton.
static WorkerService* GetInstance();
- // Initialize the WorkerService. OK to be called multiple times.
- void Initialize(ResourceDispatcherHost* rdh);
-
- // Creates a decidated worker. Returns true on success.
- bool CreateDedicatedWorker(const GURL &url,
- bool is_off_the_record,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int parent_process_id,
- int parent_appcache_host_id,
- ChromeURLRequestContext* request_context);
-
- // Creates a shared worker. Returns true on success.
- bool CreateSharedWorker(const GURL &url,
- bool is_off_the_record,
- const string16& name,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context);
-
- // Validates the passed URL and checks for the existence of matching shared
- // worker. Returns true if the url was found, and sets the url_mismatch out
- // param to true/false depending on whether there's a url mismatch with an
- // existing shared worker with the same name.
- bool LookupSharedWorker(const GURL &url,
- const string16& name,
+ // These methods correspond to worker related IPCs.
+ void CreateWorker(const ViewHostMsg_CreateWorker_Params& params,
+ int route_id,
+ WorkerMessageFilter* filter,
+ URLRequestContextGetter* request_context);
+ void LookupSharedWorker(const ViewHostMsg_CreateWorker_Params& params,
+ int route_id,
+ WorkerMessageFilter* filter,
bool off_the_record,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- bool* url_mismatch);
-
- // Notification from the renderer that a given document has detached, so any
- // associated shared workers can be shut down.
- void DocumentDetached(IPC::Message::Sender* sender,
- unsigned long long document_id);
-
- // Cancel creation of a dedicated worker that hasn't started yet.
- void CancelCreateDedicatedWorker(IPC::Message::Sender* sender,
- int sender_route_id);
-
- // Called by the worker creator when a message arrives that should be
- // forwarded to the worker process.
- void ForwardMessage(const IPC::Message& message,
- IPC::Message::Sender* sender);
+ bool* exists,
+ bool* url_error);
+ void CancelCreateDedicatedWorker(int route_id, WorkerMessageFilter* filter);
+ void ForwardToWorker(const IPC::Message& message,
+ WorkerMessageFilter* filter);
+ void DocumentDetached(unsigned long long document_id,
+ WorkerMessageFilter* filter);
+
+ void OnWorkerMessageFilterClosing(WorkerMessageFilter* filter);
int next_worker_route_id() { return ++next_worker_route_id_; }
+ // Given a worker's process id, return the IDs of the renderer process and
+ // render view that created it. For shared workers, this returns the first
+ // parent.
// TODO(dimich): This code assumes there is 1 worker per worker process, which
// is how it is today until V8 can run in separate threads.
+ bool GetRendererForWorker(int worker_process_id,
+ int* render_process_id,
+ int* render_view_id) const;
const WorkerProcessHost::WorkerInstance* FindWorkerInstance(
int worker_process_id);
- WorkerProcessHost::WorkerInstance* FindSharedWorkerInstance(
- const GURL& url, const string16& name, bool off_the_record);
-
// Used when multiple workers can run in the same process.
static const int kMaxWorkerProcessesWhenSharing;
@@ -101,20 +68,6 @@ class WorkerService : public NotificationObserver {
WorkerService();
~WorkerService();
- bool CreateWorker(const GURL &url,
- bool is_shared,
- bool is_off_the_record,
- const string16& name,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int parent_process_id,
- int parent_appcache_host_id,
- int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context);
-
// Given a WorkerInstance, create an associated worker process.
bool CreateWorkerFromInstance(WorkerProcessHost::WorkerInstance instance);
@@ -139,18 +92,10 @@ class WorkerService : public NotificationObserver {
// worker process based on the process limit when we're using a strategy of
// one worker per process.
bool TabCanCreateWorkerProcess(
- int renderer_id, int render_view_route_id, bool* hit_total_worker_limit);
+ int render_process_id, int render_route_id, bool* hit_total_worker_limit);
- // NotificationObserver interface.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Notifies us that a process that's talking to a worker has shut down.
- void SenderShutdown(IPC::Message::Sender* sender);
-
- // Notifies us that a worker process has closed.
- void WorkerProcessDestroyed(WorkerProcessHost* process);
+ // Tries to see if any of the queued workers can be created.
+ void TryStartingQueuedWorker();
// APIs for manipulating our set of pending shared worker instances.
WorkerProcessHost::WorkerInstance* CreatePendingInstance(
@@ -160,9 +105,11 @@ class WorkerService : public NotificationObserver {
void RemovePendingInstances(
const GURL& url, const string16& name, bool off_the_record);
+ WorkerProcessHost::WorkerInstance* FindSharedWorkerInstance(
+ const GURL& url, const string16& name, bool off_the_record);
+
NotificationRegistrar registrar_;
int next_worker_route_id_;
- ResourceDispatcherHost* resource_dispatcher_host_;
WorkerProcessHost::Instances queued_workers_;