diff options
9 files changed, 79 insertions, 42 deletions
diff --git a/chrome/browser/automation/extension_port_container.cc b/chrome/browser/automation/extension_port_container.cc index 15c2c8e..581da75 100644 --- a/chrome/browser/automation/extension_port_container.cc +++ b/chrome/browser/automation/extension_port_container.cc @@ -34,7 +34,7 @@ ExtensionPortContainer::~ExtensionPortContainer() { DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); if (port_id_ != -1) - service_->CloseAutomationChannel(port_id_); + service_->CloseChannel(port_id_); } bool ExtensionPortContainer::PostResponseToExternalPort( diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc index 7a65078..0ee4579 100644 --- a/chrome/browser/extensions/extension_message_service.cc +++ b/chrome/browser/extensions/extension_message_service.cc @@ -290,13 +290,28 @@ int ExtensionMessageService::OpenAutomationChannelToExtension( return port2_id; } -void ExtensionMessageService::CloseAutomationChannel(int port_id) { +void ExtensionMessageService::CloseChannel(int port_id) { DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); - // TODO(siggi): Cleanup from the tab seems to beat this to the punch. - // DCHECK(channels_[GET_CHANNEL_ID(port_id)].port1 != NULL); - // TODO(siggi): should we notify the other side of the port? - channels_.erase(GET_CHANNEL_ID(port_id)); + // Note: The channel might be gone already, if the other side closed first. + MessageChannelMap::iterator it = channels_.find(GET_CHANNEL_ID(port_id)); + if (it != channels_.end()) + CloseChannelImpl(it, port_id); +} + +void ExtensionMessageService::CloseChannelImpl( + MessageChannelMap::iterator channel_iter, int port_id) { + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + + // Notify the other side. + if (port_id == GET_CHANNEL_PORT1(channel_iter->first)) { + DispatchOnDisconnect(channel_iter->second.port2, port_id); + } else { + DCHECK_EQ(port_id, GET_CHANNEL_PORT2(channel_iter->first)); + DispatchOnDisconnect(channel_iter->second.port1, port_id); + } + + channels_.erase(channel_iter); } void ExtensionMessageService::PostMessageFromRenderer( @@ -365,13 +380,9 @@ void ExtensionMessageService::Observe(NotificationType type, it != channels_.end(); ) { MessageChannelMap::iterator current = it++; if (current->second.port1 == renderer) { - DispatchOnDisconnect(current->second.port2, - GET_CHANNEL_PORT1(current->first)); - channels_.erase(current); + CloseChannelImpl(current, GET_CHANNEL_PORT1(current->first)); } else if (current->second.port2 == renderer) { - DispatchOnDisconnect(current->second.port1, - GET_CHANNEL_PORT2(current->first)); - channels_.erase(current); + CloseChannelImpl(current, GET_CHANNEL_PORT2(current->first)); } } } diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h index dde7280..f128103 100644 --- a/chrome/browser/extensions/extension_message_service.h +++ b/chrome/browser/extensions/extension_message_service.h @@ -54,22 +54,17 @@ class ExtensionMessageService : public NotificationObserver { void AddEventListener(std::string event_name, int render_process_id); void RemoveEventListener(std::string event_name, int render_process_id); - // Closes an extension channel for test automation. - void CloseAutomationChannel(int port_id); + // Closes the message channel associated with the given port, and notifies + // the other side. + void CloseChannel(int port_id); // Sends a message from a renderer to the given port. - // TODO(mpcomplete): include the source tab. void PostMessageFromRenderer(int port_id, const std::string& message); // Send an event to every registered extension renderer. void DispatchEventToRenderers( const std::string& event_name, const std::string& event_args); - // NotificationObserver interface. - void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - // Given an extension's ID, opens a channel between the given automation // "port" and that extension. Returns a channel ID to be used for posting // messages between the processes, or -1 if the extension doesn't exist. @@ -78,6 +73,11 @@ class ExtensionMessageService : public NotificationObserver { const std::string& extension_id, IPC::Message::Sender* source); + // NotificationObserver interface. + void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + // --- IO thread only: // Given an extension's ID, opens a channel between the given renderer "port" @@ -89,6 +89,16 @@ class ExtensionMessageService : public NotificationObserver { ResourceMessageFilter* source); private: + // The connection between two ports. It is possible that both ports + // refer to the same renderer. + struct MessageChannel { + IPC::Message::Sender* port1; + IPC::Message::Sender* port2; + }; + + // A map of channel ID to its channel object. + typedef std::map<int, MessageChannel> MessageChannelMap; + // Allocates a pair of port ids. // NOTE: this can be called from any thread. void AllocatePortIdPair(int* port1, int* port2); @@ -97,6 +107,8 @@ class ExtensionMessageService : public NotificationObserver { // NOTE: this can be called from any thread. int GetProcessIdForExtension(const std::string& extension_id); + void CloseChannelImpl(MessageChannelMap::iterator channel_iter, int port_id); + int OpenChannelToExtensionImpl(const std::string& extension_id, IPC::Message::Sender* source); @@ -136,15 +148,6 @@ class ExtensionMessageService : public NotificationObserver { int source_routing_id, int source_port_id, IPC::Message::Sender* source, int dest_port_id, int dest_process_id, int source_process_id); - // The connection between two ports. It is possible that both ports - // refer to the same renderer. - struct MessageChannel { - IPC::Message::Sender* port1; - IPC::Message::Sender* port2; - }; - - // A map of channel ID to its channel object. - typedef std::map<int, MessageChannel> MessageChannelMap; MessageChannelMap channels_; // True if Init has been called. diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 03c961a..a462862 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -671,6 +671,8 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) { OnExtensionAddListener) IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionRemoveListener, OnExtensionRemoveListener) + IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionCloseChannel, + OnExtensionCloseChannel) IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP_EX() @@ -887,14 +889,17 @@ void BrowserRenderProcessHost::Observe(NotificationType type, void BrowserRenderProcessHost::OnExtensionAddListener( const std::string& event_name) { - URLRequestContext* context = profile()->GetRequestContext(); - ExtensionMessageService* ems = ExtensionMessageService::GetInstance(context); - ems->AddEventListener(event_name, pid()); + ExtensionMessageService::GetInstance(profile()->GetRequestContext())-> + AddEventListener(event_name, pid()); } void BrowserRenderProcessHost::OnExtensionRemoveListener( const std::string& event_name) { - URLRequestContext* context = profile()->GetRequestContext(); - ExtensionMessageService* ems = ExtensionMessageService::GetInstance(context); - ems->RemoveEventListener(event_name, pid()); + ExtensionMessageService::GetInstance(profile()->GetRequestContext())-> + RemoveEventListener(event_name, pid()); +} + +void BrowserRenderProcessHost::OnExtensionCloseChannel(int port_id) { + ExtensionMessageService::GetInstance(profile()->GetRequestContext())-> + CloseChannel(port_id); } diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h index aee8d2b..d92d9fd 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.h +++ b/chrome/browser/renderer_host/browser_render_process_host.h @@ -87,16 +87,15 @@ class BrowserRenderProcessHost : public RenderProcessHost, const NotificationSource& source, const NotificationDetails& details); - // An extension process started or stopped listening to an event. - void OnExtensionAddListener(const std::string& event_name); - void OnExtensionRemoveListener(const std::string& event_name); - private: // Control message handlers. void OnPageContents(const GURL& url, int32 page_id, const std::wstring& contents); void OnUpdatedCacheStats(const WebKit::WebCache::UsageStats& stats); void SuddenTerminationChanged(bool enabled); + void OnExtensionAddListener(const std::string& event_name); + void OnExtensionRemoveListener(const std::string& event_name); + void OnExtensionCloseChannel(int port_id); // Initialize support for visited links. Send the renderer process its initial // set of visited links. diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index a1bcff2..c8de0fe 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1383,6 +1383,11 @@ IPC_BEGIN_MESSAGES(ViewHost) int /* port_id */, std::string /* message */) + // Send a message to an extension process. The handle is the value returned + // by ViewHostMsg_OpenChannelToExtension. + IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionCloseChannel, + int /* port_id */) + // Message to show a popup menu using native cocoa controls (Mac only). IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowPopup, ViewHostMsg_ShowPopup_Params) diff --git a/chrome/renderer/extensions/event_bindings.h b/chrome/renderer/extensions/event_bindings.h index f2c5f88..285a379 100644 --- a/chrome/renderer/extensions/event_bindings.h +++ b/chrome/renderer/extensions/event_bindings.h @@ -27,8 +27,8 @@ class EventBindings { static void HandleContextDestroyed(WebFrame* frame); // Calls the given function in each registered context which is listening - // for events. The function can be an object property, ie: - // "chromium.Event.dispatch_". + // for events. See comments on bindings_utils::CallFunctionInContext for + // more details. static void CallFunction(const std::string& function_name, int argc, v8::Handle<v8::Value>* argv); diff --git a/chrome/renderer/extensions/renderer_extension_bindings.cc b/chrome/renderer/extensions/renderer_extension_bindings.cc index f719797..4cff1dd 100644 --- a/chrome/renderer/extensions/renderer_extension_bindings.cc +++ b/chrome/renderer/extensions/renderer_extension_bindings.cc @@ -46,6 +46,8 @@ class ExtensionImpl : public ExtensionBase { return v8::FunctionTemplate::New(OpenChannelToExtension); } else if (name->Equals(v8::String::New("PostMessage"))) { return v8::FunctionTemplate::New(PostMessage); + } else if (name->Equals(v8::String::New("CloseChannel"))) { + return v8::FunctionTemplate::New(CloseChannel); } return ExtensionBase::GetNativeFunction(name); } @@ -83,6 +85,17 @@ class ExtensionImpl : public ExtensionBase { } return v8::Undefined(); } + + // Sends a message along the given channel. + static v8::Handle<v8::Value> CloseChannel(const v8::Arguments& args) { + if (args.Length() >= 1 && args[0]->IsInt32()) { + int port_id = args[0]->Int32Value(); + // Send via the RenderThread because the RenderView might be closing. + EventBindings::GetRenderThread()->Send( + new ViewHostMsg_ExtensionCloseChannel(port_id)); + } + return v8::Undefined(); + } }; // Convert a ListValue to a vector of V8 values. diff --git a/chrome/renderer/resources/renderer_extension_bindings.js b/chrome/renderer/resources/renderer_extension_bindings.js index bf59671..f9d354e 100644 --- a/chrome/renderer/resources/renderer_extension_bindings.js +++ b/chrome/renderer/resources/renderer_extension_bindings.js @@ -10,6 +10,7 @@ var chrome = chrome || {}; (function () { native function OpenChannelToExtension(id); + native function CloseChannel(portId); native function PostMessage(portId, msg); native function GetChromeHidden(); @@ -78,7 +79,7 @@ var chrome = chrome || {}; // Disconnects the port from the other end. chrome.Port.prototype.disconnect = function() { delete ports[this.portId_]; - //CloseChannel(this.portId_); // TODO(mpcomplete) + CloseChannel(this.portId_); } // Extension object. |