Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4297)

Unified Diff: chrome/browser/extensions/extension_message_service.cc

Issue 155707: Changed the extension.connect() API not to broadcast to all tabs. Added a (Closed)
Patch Set: review comments Created 11 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
- }
}
« no previous file with comments | « chrome/browser/extensions/extension_message_service.h ('k') | chrome/browser/extensions/extension_messages_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698