diff options
Diffstat (limited to 'chrome/browser/worker_host')
-rw-r--r-- | chrome/browser/worker_host/message_port_dispatcher.cc | 292 | ||||
-rw-r--r-- | chrome/browser/worker_host/message_port_dispatcher.h | 93 | ||||
-rw-r--r-- | chrome/browser/worker_host/message_port_service.cc | 236 | ||||
-rw-r--r-- | chrome/browser/worker_host/message_port_service.h | 75 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_document_set.cc | 35 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_document_set.h | 41 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_message_filter.cc | 116 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_message_filter.h | 62 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_process_host.cc | 449 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_process_host.h | 134 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_service.cc | 515 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_service.h | 119 |
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_; |