| 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);
|
| - }
|
| }
|
|
|