summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension_message_service.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions/extension_message_service.cc')
-rwxr-xr-xchrome/browser/extensions/extension_message_service.cc154
1 files changed, 75 insertions, 79 deletions
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc
index 95143ce..87469f9 100755
--- a/chrome/browser/extensions/extension_message_service.cc
+++ b/chrome/browser/extensions/extension_message_service.cc
@@ -13,121 +13,117 @@
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/render_messages.h"
-// This class acts as the port to an extension process. It is basically just
-// gymnastics to get access to the IPC::Channel (not the ChannelProxy) belonging
-// to an ExtensionView.
-// Created on the UI thread, but accessed fully on the IO thread.
-class ExtensionMessageService::ExtensionFilter :
- public IPC::ChannelProxy::MessageFilter {
- public:
- ExtensionFilter(const std::string& extension_id, int routing_id) :
- extension_id_(extension_id), routing_id_(routing_id), channel_(NULL) {
- }
- ~ExtensionFilter() {
- ExtensionMessageService::GetInstance()->OnExtensionUnregistered(this);
- }
-
- virtual void OnFilterAdded(IPC::Channel* channel) {
- channel_ = channel;
- ExtensionMessageService::GetInstance()->OnExtensionRegistered(this);
- }
- virtual void OnChannelClosing() {
- channel_ = NULL;
- }
-
- bool Send(IPC::Message* message) {
- if (!channel_) {
- delete message;
- return false;
- }
- return channel_->Send(message);
- }
+// Since we have 2 ports for every channel, we just index channels by half the
+// port ID.
+#define GET_CHANNEL_ID(port_id) (port_id / 2)
- IPC::Channel* channel() { return channel_; }
- const std::string& extension_id() { return extension_id_; }
- int routing_id() { return routing_id_; }
+// Port1 is always even, port2 is always odd.
+#define IS_PORT1_ID(port_id) ((port_id & 1) == 0)
- private:
- std::string extension_id_;
- int routing_id_;
- IPC::Channel* channel_;
-};
+// Change even to odd and vice versa, to get the other side of a given channel.
+#define GET_OPPOSITE_PORT_ID(source_port_id) (source_port_id ^ 1)
ExtensionMessageService* ExtensionMessageService::GetInstance() {
return Singleton<ExtensionMessageService>::get();
}
ExtensionMessageService::ExtensionMessageService()
- : next_channel_id_(0) {
+ : next_port_id_(0) {
}
-void ExtensionMessageService::RegisterExtensionView(ExtensionView* view) {
- view->render_view_host()->process()->channel()->AddFilter(
- new ExtensionFilter(view->extension()->id(),
- view->render_view_host()->routing_id()));
-}
-
-void ExtensionMessageService::OnExtensionRegistered(ExtensionFilter* filter) {
- extensions_[filter->extension_id()] = filter;
-}
-
-void ExtensionMessageService::OnExtensionUnregistered(ExtensionFilter* filter) {
- // TODO(mpcomplete): support multiple filters per extension_id
- //DCHECK(extensions_[filter->extension_id()] == filter);
- extensions_.erase(filter->extension_id());
-
- // Close any channels that share this filter.
- for (MessageChannelMap::iterator it = channels_.begin();
- it != channels_.end(); ) {
- MessageChannelMap::iterator current = it++;
- if (current->second.extension_port == filter)
- channels_.erase(current);
- }
+void ExtensionMessageService::RegisterExtension(
+ const std::string& extension_id, int render_process_id) {
+ AutoLock lock(renderers_lock_);
+ // TODO(mpcomplete): We need to ensure an extension always ends up in a single
+ // process. I think this means having an ExtensionProcessManager which holds
+ // a BrowsingContext for each extension.
+ //DCHECK(process_ids_.find(extension_id) == process_ids_.end());
+ process_ids_[extension_id] = render_process_id;
}
int ExtensionMessageService::OpenChannelToExtension(
- const std::string& extension_id, ResourceMessageFilter* renderer_port) {
+ const std::string& extension_id, ResourceMessageFilter* source) {
DCHECK(MessageLoop::current() ==
ChromeThread::GetMessageLoop(ChromeThread::IO));
- ExtensionMap::iterator extension_port = extensions_.find(extension_id);
- if (extension_port == extensions_.end())
- return -1;
+ // Lookup the targeted extension process.
+ ResourceMessageFilter* dest = NULL;
+ {
+ AutoLock lock(renderers_lock_);
+ ProcessIDMap::iterator process_id = process_ids_.find(extension_id);
+ if (process_id == process_ids_.end())
+ return -1;
+
+ RendererMap::iterator renderer = renderers_.find(process_id->second);
+ if (renderer == renderers_.end())
+ return -1;
+ dest = renderer->second;
+ }
+
+ // Create a channel ID for both sides of the channel.
+ int port1_id = next_port_id_++;
+ int port2_id = next_port_id_++;
+ DCHECK(IS_PORT1_ID(port1_id));
+ DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id);
+ DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id);
+ DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id));
- int channel_id = next_channel_id_++;
MessageChannel channel;
- channel.renderer_port = renderer_port;
- channel.extension_port = extension_port->second;
- channels_[channel_id] = channel;
+ channel.port1 = source;
+ channel.port2 = dest;
+ channels_[GET_CHANNEL_ID(port1_id)] = channel;
- return channel_id;
+ // Send each process the id for the opposite port.
+ dest->Send(new ViewMsg_ExtensionHandleConnect(port1_id));
+ return port2_id;
}
-void ExtensionMessageService::PostMessageToExtension(
- int channel_id, const std::string& message) {
+void ExtensionMessageService::PostMessageFromRenderer(
+ int port_id, const std::string& message, ResourceMessageFilter* source) {
DCHECK(MessageLoop::current() ==
ChromeThread::GetMessageLoop(ChromeThread::IO));
- MessageChannelMap::iterator iter = channels_.find(channel_id);
+ // Look up the channel by port1's ID.
+ MessageChannelMap::iterator iter =
+ channels_.find(GET_CHANNEL_ID(port_id));
if (iter == channels_.end())
return;
-
MessageChannel& channel = iter->second;
- channel.extension_port->Send(new ViewMsg_HandleExtensionMessage(
- channel.extension_port->routing_id(), message, channel_id));
+
+ // Figure out which port the ID corresponds to.
+ ResourceMessageFilter* dest = NULL;
+ if (IS_PORT1_ID(port_id)) {
+ dest = channel.port1;
+ DCHECK(source == channel.port2);
+ } else {
+ dest = channel.port2;
+ DCHECK(source == channel.port1);
+ }
+
+ int source_port_id = GET_OPPOSITE_PORT_ID(port_id);
+ dest->Send(new ViewMsg_ExtensionHandleMessage(message, source_port_id));
+}
+
+void ExtensionMessageService::RendererReady(ResourceMessageFilter* renderer) {
+ AutoLock lock(renderers_lock_);
+ DCHECK(renderers_.find(renderer->GetProcessId()) == renderers_.end());
+ renderers_[renderer->GetProcessId()] = renderer;
}
void ExtensionMessageService::RendererShutdown(
- ResourceMessageFilter* renderer_port) {
- DCHECK(MessageLoop::current() ==
- ChromeThread::GetMessageLoop(ChromeThread::IO));
+ ResourceMessageFilter* renderer) {
+ {
+ AutoLock lock(renderers_lock_);
+ DCHECK(renderers_.find(renderer->GetProcessId()) != renderers_.end());
+ renderers_.erase(renderer->GetProcessId());
+ }
// Close any channels that share this filter.
// TODO(mpcomplete): should we notify the other side of the port?
for (MessageChannelMap::iterator it = channels_.begin();
it != channels_.end(); ) {
MessageChannelMap::iterator current = it++;
- if (current->second.renderer_port == renderer_port)
+ if (current->second.port1 == renderer || current->second.port2 == renderer)
channels_.erase(current);
}
}