Index: chrome/browser/extensions/extension_message_service.cc |
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc |
index 70bfda772262ccdd71275d21daf61a6beef095c9..326701bcd052e9aebfbb3bfdce56b8a96e0c56e0 100644 |
--- a/chrome/browser/extensions/extension_message_service.cc |
+++ b/chrome/browser/extensions/extension_message_service.cc |
@@ -10,7 +10,9 @@ |
#include "base/values.h" |
#include "chrome/browser/child_process_security_policy.h" |
#include "chrome/browser/chrome_thread.h" |
+#include "chrome/browser/extensions/extension_process_manager.h" |
#include "chrome/browser/extensions/extension_tabs_module.h" |
+#include "chrome/browser/profile.h" |
#include "chrome/browser/renderer_host/render_process_host.h" |
#include "chrome/browser/renderer_host/render_view_host.h" |
#include "chrome/browser/renderer_host/resource_message_filter.h" |
@@ -32,17 +34,25 @@ |
// 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) |
-namespace { |
-typedef std::map<URLRequestContext*, ExtensionMessageService*> InstanceMap; |
-struct SingletonData { |
- ~SingletonData() { |
- STLDeleteContainerPairSecondPointers(map.begin(), map.end()); |
- } |
- Lock lock; |
- InstanceMap map; |
+struct ExtensionMessageService::MessagePort { |
+ IPC::Message::Sender* sender; |
+ int routing_id; |
+ |
+ MessagePort(IPC::Message::Sender* sender = NULL, |
+ int routing_id = MSG_ROUTING_CONTROL) : |
+ sender(sender), routing_id(routing_id) {} |
+}; |
+ |
+struct ExtensionMessageService::MessageChannel { |
+ ExtensionMessageService::MessagePort opener; |
+ ExtensionMessageService::MessagePort receiver; |
}; |
-static void DispatchOnConnect(IPC::Message::Sender* channel, int dest_port_id, |
+ |
+namespace { |
+ |
+static void DispatchOnConnect(const ExtensionMessageService::MessagePort& port, |
+ int dest_port_id, |
const std::string& channel_name, |
const std::string& tab_json, |
const std::string& extension_id) { |
@@ -51,51 +61,39 @@ static void DispatchOnConnect(IPC::Message::Sender* channel, int dest_port_id, |
args.Set(1, Value::CreateStringValue(channel_name)); |
args.Set(2, Value::CreateStringValue(tab_json)); |
args.Set(3, Value::CreateStringValue(extension_id)); |
- channel->Send(new ViewMsg_ExtensionMessageInvoke( |
- ExtensionMessageService::kDispatchOnConnect, args)); |
+ port.sender->Send(new ViewMsg_ExtensionMessageInvoke( |
+ port.routing_id, ExtensionMessageService::kDispatchOnConnect, args)); |
} |
-static void DispatchOnDisconnect(IPC::Message::Sender* channel, |
- int source_port_id) { |
+static void DispatchOnDisconnect( |
+ const ExtensionMessageService::MessagePort& port, int source_port_id) { |
ListValue args; |
args.Set(0, Value::CreateIntegerValue(source_port_id)); |
- channel->Send(new ViewMsg_ExtensionMessageInvoke( |
- ExtensionMessageService::kDispatchOnDisconnect, args)); |
+ port.sender->Send(new ViewMsg_ExtensionMessageInvoke( |
+ port.routing_id, ExtensionMessageService::kDispatchOnDisconnect, args)); |
} |
-static void DispatchOnMessage(IPC::Message::Sender* channel, |
+static void DispatchOnMessage(const ExtensionMessageService::MessagePort& port, |
const std::string& message, int source_port_id) { |
ListValue args; |
args.Set(0, Value::CreateStringValue(message)); |
args.Set(1, Value::CreateIntegerValue(source_port_id)); |
- channel->Send(new ViewMsg_ExtensionMessageInvoke( |
- ExtensionMessageService::kDispatchOnMessage, args)); |
+ port.sender->Send(new ViewMsg_ExtensionMessageInvoke( |
+ port.routing_id, ExtensionMessageService::kDispatchOnMessage, args)); |
} |
-static void DispatchEvent(IPC::Message::Sender* channel, |
+static void DispatchEvent(const ExtensionMessageService::MessagePort& port, |
const std::string& event_name, |
const std::string& event_args) { |
ListValue args; |
args.Set(0, Value::CreateStringValue(event_name)); |
args.Set(1, Value::CreateStringValue(event_args)); |
- channel->Send(new ViewMsg_ExtensionMessageInvoke( |
- ExtensionMessageService::kDispatchEvent, args)); |
-} |
- |
-static std::string GetChannelConnectEvent(const std::string& extension_id) { |
- return StringPrintf("channel-connect:%s", extension_id.c_str()); |
+ port.sender->Send(new ViewMsg_ExtensionMessageInvoke( |
+ port.routing_id, ExtensionMessageService::kDispatchEvent, args)); |
} |
} // namespace |
-// Since ExtensionMessageService is a collection of Singletons, we don't need to |
-// grab a reference to it when creating Tasks involving it. |
-template <> struct RunnableMethodTraits<ExtensionMessageService> { |
- static void RetainCallee(ExtensionMessageService*) {} |
- static void ReleaseCallee(ExtensionMessageService*) {} |
-}; |
- |
- |
const char ExtensionMessageService::kDispatchOnConnect[] = |
"Port.dispatchOnConnect"; |
const char ExtensionMessageService::kDispatchOnDisconnect[] = |
@@ -105,37 +103,19 @@ const char ExtensionMessageService::kDispatchOnMessage[] = |
const char ExtensionMessageService::kDispatchEvent[] = |
"Event.dispatchJSON"; |
-// static |
-ExtensionMessageService* ExtensionMessageService::GetInstance( |
- URLRequestContext* context) { |
- SingletonData* data = Singleton<SingletonData>::get(); |
- AutoLock lock(data->lock); |
- |
- ExtensionMessageService* instance = data->map[context]; |
- if (!instance) { |
- instance = new ExtensionMessageService(); |
- data->map[context] = instance; |
- } |
- return instance; |
-} |
- |
-ExtensionMessageService::ExtensionMessageService() |
- : ui_loop_(NULL), initialized_(false), next_port_id_(0) { |
-} |
- |
-void ExtensionMessageService::Init() { |
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
- |
- if (initialized_) |
- return; |
- initialized_ = true; |
- |
- ui_loop_ = MessageLoop::current(); |
+ExtensionMessageService::ExtensionMessageService(Profile* profile) |
+ : ui_loop_(MessageLoop::current()), profile_(profile), next_port_id_(0) { |
+ DCHECK_EQ(ui_loop_->type(), MessageLoop::TYPE_UI); |
registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED, |
NotificationService::AllSources()); |
registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED, |
NotificationService::AllSources()); |
+ registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, |
+ NotificationService::AllSources()); |
+} |
+ |
+ExtensionMessageService::~ExtensionMessageService() { |
} |
void ExtensionMessageService::AddEventListener(std::string event_name, |
@@ -177,7 +157,6 @@ int ExtensionMessageService::OpenChannelToExtension( |
const std::string& channel_name, ResourceMessageFilter* source) { |
DCHECK_EQ(MessageLoop::current(), |
ChromeThread::GetMessageLoop(ChromeThread::IO)); |
- DCHECK(initialized_); |
// Create a channel ID for both sides of the channel. |
int port1_id = -1; |
@@ -187,51 +166,83 @@ int ExtensionMessageService::OpenChannelToExtension( |
// Each side of the port is given his own port ID. When they send messages, |
// we convert to the opposite port ID. See PostMessageFromRenderer. |
ui_loop_->PostTask(FROM_HERE, |
- NewRunnableMethod(this, &ExtensionMessageService::OpenChannelOnUIThread, |
- routing_id, port2_id, source->GetProcessId(), extension_id, |
+ NewRunnableMethod(this, |
+ &ExtensionMessageService::OpenChannelToExtensionOnUIThread, |
+ source->GetProcessId(), routing_id, port2_id, extension_id, |
+ channel_name)); |
+ |
+ return port1_id; |
+} |
+ |
+int ExtensionMessageService::OpenChannelToTab( |
+ int routing_id, int tab_id, const std::string& extension_id, |
+ const std::string& channel_name, ResourceMessageFilter* source) { |
+ DCHECK_EQ(MessageLoop::current(), |
+ ChromeThread::GetMessageLoop(ChromeThread::IO)); |
+ |
+ // Create a channel ID for both sides of the channel. |
+ int port1_id = -1; |
+ int port2_id = -1; |
+ AllocatePortIdPair(&port1_id, &port2_id); |
+ |
+ // Each side of the port is given his own port ID. When they send messages, |
+ // we convert to the opposite port ID. See PostMessageFromRenderer. |
+ ui_loop_->PostTask(FROM_HERE, |
+ NewRunnableMethod(this, |
+ &ExtensionMessageService::OpenChannelToTabOnUIThread, |
+ source->GetProcessId(), routing_id, port2_id, tab_id, extension_id, |
channel_name)); |
return port1_id; |
} |
-void ExtensionMessageService::OpenChannelOnUIThread( |
- int source_routing_id, int receivers_port_id, int source_process_id, |
+void ExtensionMessageService::OpenChannelToExtensionOnUIThread( |
+ int source_process_id, int source_routing_id, int receiver_port_id, |
const std::string& extension_id, const std::string& channel_name) { |
+ if (!profile_) |
+ return; |
+ |
RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); |
- OpenChannelOnUIThreadImpl(source_routing_id, receivers_port_id, |
- source_process_id, source, extension_id, |
+ MessagePort receiver( |
+ profile_->GetExtensionProcessManager()->GetExtensionProcess(extension_id), |
+ MSG_ROUTING_CONTROL); |
+ OpenChannelOnUIThreadImpl(source, source_process_id, source_routing_id, |
+ receiver, receiver_port_id, extension_id, |
channel_name); |
} |
-void ExtensionMessageService::OpenChannelOnUIThreadImpl( |
- int source_routing_id, int receivers_port_id, int source_process_id, |
- IPC::Message::Sender* source, const std::string& extension_id, |
+void ExtensionMessageService::OpenChannelToTabOnUIThread( |
+ int source_process_id, int source_routing_id, int receiver_port_id, |
+ int tab_id, const std::string& extension_id, |
const std::string& channel_name) { |
+ RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); |
+ TabContents* contents; |
+ MessagePort receiver; |
+ if (ExtensionTabUtil::GetTabById(tab_id, source->profile(), |
+ NULL, NULL, &contents, NULL)) { |
+ receiver.sender = contents->render_view_host(); |
+ receiver.routing_id = contents->render_view_host()->routing_id(); |
+ } |
+ OpenChannelOnUIThreadImpl(source, source_process_id, source_routing_id, |
+ receiver, receiver_port_id, extension_id, |
+ channel_name); |
+} |
+ |
+void ExtensionMessageService::OpenChannelOnUIThreadImpl( |
+ IPC::Message::Sender* source, int source_process_id, int source_routing_id, |
+ const MessagePort& receiver, int receiver_port_id, |
+ const std::string& extension_id, const std::string& channel_name) { |
DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
- if (!source) |
- return; // Source closed while task was in flight. |
+ // TODO(mpcomplete): notify source if reciever doesn't exist |
+ if (!source || !receiver.sender) |
+ return; // Closed while in flight. |
linked_ptr<MessageChannel> channel(new MessageChannel); |
- channel->opener.insert(source); |
- |
- // Get the list of processes that are listening for this extension's channel |
- // connect event. |
- std::string event_name = GetChannelConnectEvent(extension_id); |
- std::set<int>& pids = listeners_[event_name]; |
- for (std::set<int>::iterator pid = pids.begin(); pid != pids.end(); ++pid) { |
- RenderProcessHost* renderer = RenderProcessHost::FromID(*pid); |
- if (!renderer) |
- continue; |
- channel->receivers.insert(renderer); |
- } |
- if (channel->receivers.empty()) { |
- // Either no one is listening, or all listeners have since closed. |
- // TODO(mpcomplete): should we notify the source? |
- return; |
- } |
+ channel->opener = MessagePort(source, MSG_ROUTING_CONTROL); |
+ channel->receiver = receiver; |
- channels_[GET_CHANNEL_ID(receivers_port_id)] = channel; |
+ channels_[GET_CHANNEL_ID(receiver_port_id)] = channel; |
// Include info about the opener's tab (if it was a tab). |
std::string tab_json = "null"; |
@@ -242,20 +253,17 @@ void ExtensionMessageService::OpenChannelOnUIThreadImpl( |
JSONWriter::Write(tab_value, false, &tab_json); |
} |
- // Broadcast the connect event to the receivers. Give them the opener's |
- // port ID (the opener has the opposite port ID). |
- for (MessageChannel::Ports::iterator it = channel->receivers.begin(); |
- it != channel->receivers.end(); ++it) { |
- DispatchOnConnect(*it, receivers_port_id, channel_name, tab_json, |
- extension_id); |
- } |
+ // Send the connect event to the receiver. Give it the opener's port ID (the |
+ // opener has the opposite port ID). |
+ DispatchOnConnect(receiver, receiver_port_id, channel_name, tab_json, |
+ extension_id); |
} |
int ExtensionMessageService::OpenAutomationChannelToExtension( |
int source_process_id, int routing_id, const std::string& extension_id, |
IPC::Message::Sender* source) { |
DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
- DCHECK(initialized_); |
+ DCHECK(profile_); |
int port1_id = -1; |
int port2_id = -1; |
@@ -267,8 +275,11 @@ int ExtensionMessageService::OpenAutomationChannelToExtension( |
// This isn't really appropriate here, the originating tab |
// information should be supplied by the caller for |
// automation-initiated ports. |
- OpenChannelOnUIThreadImpl(routing_id, port2_id, source_process_id, |
- source, extension_id, ""); |
+ MessagePort receiver( |
+ profile_->GetExtensionProcessManager()->GetExtensionProcess(extension_id), |
+ MSG_ROUTING_CONTROL); |
+ OpenChannelOnUIThreadImpl(source, source_process_id, routing_id, receiver, |
+ port2_id, extension_id, ""); |
return port1_id; |
} |
@@ -287,15 +298,10 @@ void ExtensionMessageService::CloseChannelImpl( |
DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
// Notify the other side. |
- MessageChannel::Ports* ports = |
- IS_OPENER_PORT_ID(closing_port_id) ? |
- &channel_iter->second->receivers : &channel_iter->second->opener; |
- |
- for (MessageChannel::Ports::iterator it = ports->begin(); |
- it != ports->end(); ++it) { |
- DispatchOnDisconnect(*it, GET_OPPOSITE_PORT_ID(closing_port_id)); |
- } |
+ const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? |
+ channel_iter->second->receiver : channel_iter->second->opener; |
+ DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id)); |
channels_.erase(channel_iter); |
} |
@@ -310,14 +316,10 @@ void ExtensionMessageService::PostMessageFromRenderer( |
// Figure out which port the ID corresponds to. |
int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id); |
- MessageChannel::Ports* ports = |
- IS_OPENER_PORT_ID(dest_port_id) ? |
- &iter->second->opener : &iter->second->receivers; |
+ const MessagePort& port = IS_OPENER_PORT_ID(dest_port_id) ? |
+ iter->second->opener : iter->second->receiver; |
- for (MessageChannel::Ports::iterator it = ports->begin(); |
- it != ports->end(); ++it) { |
- DispatchOnMessage(*it, message, dest_port_id); |
- } |
+ DispatchOnMessage(port, message, dest_port_id); |
} |
void ExtensionMessageService::DispatchEventToRenderers( |
@@ -346,29 +348,41 @@ void ExtensionMessageService::Observe(NotificationType type, |
const NotificationDetails& details) { |
DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
- DCHECK(type.value == NotificationType::RENDERER_PROCESS_TERMINATED || |
- type.value == NotificationType::RENDERER_PROCESS_CLOSED); |
- |
- RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); |
+ switch (type.value) { |
+ case NotificationType::RENDERER_PROCESS_TERMINATED: |
+ case NotificationType::RENDERER_PROCESS_CLOSED: { |
+ RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); |
+ OnSenderClosed(renderer); |
+ |
+ // Remove this renderer from our listener maps. |
+ for (ListenerMap::iterator it = listeners_.begin(); |
+ it != listeners_.end(); ) { |
+ ListenerMap::iterator current = it++; |
+ current->second.erase(renderer->pid()); |
+ if (current->second.empty()) |
+ listeners_.erase(current); |
+ } |
+ break; |
+ } |
+ case NotificationType::RENDER_VIEW_HOST_DELETED: |
+ OnSenderClosed(Details<RenderViewHost>(details).ptr()); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ return; |
+ } |
+} |
+void ExtensionMessageService::OnSenderClosed(IPC::Message::Sender* sender) { |
// Close any channels that share this renderer. We notify the opposite |
// port that his pair has closed. |
for (MessageChannelMap::iterator it = channels_.begin(); |
it != channels_.end(); ) { |
MessageChannelMap::iterator current = it++; |
- if (current->second->opener.count(renderer) > 0) { |
+ if (current->second->opener.sender == sender) { |
CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first)); |
- } else if (current->second->receivers.count(renderer) > 0) { |
+ } else if (current->second->receiver.sender == sender) { |
CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first)); |
} |
} |
- |
- // Remove this renderer from our listener maps. |
- for (ListenerMap::iterator it = listeners_.begin(); |
- it != listeners_.end(); ) { |
- ListenerMap::iterator current = it++; |
- current->second.erase(renderer->pid()); |
- if (current->second.empty()) |
- listeners_.erase(current); |
- } |
} |