diff options
author | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-01 21:17:49 +0000 |
---|---|---|
committer | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-01 21:17:49 +0000 |
commit | 4b5d64ff3d7d95247ed4f078d8bf585a1726794d (patch) | |
tree | 050a523a5bbccf28ade0814b38bcc9bee187cd04 /chrome | |
parent | 912445b6db66140aecb3bc822075a6e9bb9d7e33 (diff) | |
download | chromium_src-4b5d64ff3d7d95247ed4f078d8bf585a1726794d.zip chromium_src-4b5d64ff3d7d95247ed4f078d8bf585a1726794d.tar.gz chromium_src-4b5d64ff3d7d95247ed4f078d8bf585a1726794d.tar.bz2 |
Pass down the opener tab when a message channel is opened to an extension.
Also did a bunch of cleanup of ExtensionMessageService. I converted it to
primarily UI-thread habitation, with one function that needs to be on the IO
thread so it can handle a synchronous IPC message.
TEST=N/A
Review URL: http://codereview.chromium.org/99261
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15097 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
25 files changed, 281 insertions, 200 deletions
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc index 4e9daba..95dd221 100755 --- a/chrome/browser/extensions/extension_message_service.cc +++ b/chrome/browser/extensions/extension_message_service.cc @@ -4,14 +4,18 @@ #include "chrome/browser/extensions/extension_message_service.h" +#include "base/json_writer.h" #include "base/singleton.h" #include "base/values.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/extensions/extension.h" +#include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extension_view.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/resource_message_filter.h" +#include "chrome/browser/tab_contents/tab_util.h" +#include "chrome/browser/tab_contents/web_contents.h" #include "chrome/common/notification_service.h" #include "chrome/common/render_messages.h" #include "chrome/common/stl_util-inl.h" @@ -59,12 +63,35 @@ ExtensionMessageService* ExtensionMessageService::GetInstance( } ExtensionMessageService::ExtensionMessageService() - : next_port_id_(0), observing_renderer_shutdown_(false) { + : 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(); + + // Note: we never stop observing because we live longer than + // NotificationService. + NotificationService::current()->AddObserver(this, + NotificationType::RENDERER_PROCESS_TERMINATED, + NotificationService::AllSources()); + NotificationService::current()->AddObserver(this, + NotificationType::RENDERER_PROCESS_CRASHED, + NotificationService::AllSources()); } void ExtensionMessageService::RegisterExtension( const std::string& extension_id, int render_process_id) { - DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + + // Make sure we're initialized. + Init(); + AutoLock lock(process_ids_lock_); DCHECK(process_ids_.find(extension_id) == process_ids_.end() || process_ids_[extension_id] == render_process_id); @@ -73,24 +100,23 @@ void ExtensionMessageService::RegisterExtension( void ExtensionMessageService::AddEventListener(std::string event_name, int render_process_id) { - DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); - AutoLock lock(listener_lock_); + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); DCHECK(listeners_[event_name].count(render_process_id) == 0); listeners_[event_name].insert(render_process_id); } void ExtensionMessageService::RemoveEventListener(std::string event_name, int render_process_id) { - DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); - AutoLock lock(listener_lock_); + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); DCHECK(listeners_[event_name].count(render_process_id) == 1); listeners_[event_name].erase(render_process_id); } int ExtensionMessageService::OpenChannelToExtension( - const std::string& extension_id, ResourceMessageFilter* source) { - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); + int routing_id, const std::string& extension_id, + ResourceMessageFilter* source) { + DCHECK_EQ(MessageLoop::current(), + ChromeThread::GetMessageLoop(ChromeThread::IO)); // Lookup the targeted extension process. int process_id; @@ -103,13 +129,10 @@ int ExtensionMessageService::OpenChannelToExtension( process_id = process_id_it->second; } - RendererMap::iterator renderer = renderers_.find(process_id); - if (renderer == renderers_.end()) - return -1; - - ResourceMessageFilter* dest = renderer->second; + DCHECK(initialized_); // Create a channel ID for both sides of the channel. + // TODO(mpcomplete): what happens when this wraps? int port1_id = next_port_id_++; int port2_id = next_port_id_++; DCHECK(IS_PORT1_ID(port1_id)); @@ -117,22 +140,45 @@ int ExtensionMessageService::OpenChannelToExtension( DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id); DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id)); + ui_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &ExtensionMessageService::OpenChannelOnUIThread, + routing_id, port1_id, source->GetProcessId(), port2_id, process_id)); + + return port2_id; +} + +void ExtensionMessageService::OpenChannelOnUIThread( + int source_routing_id, int source_port_id, int source_process_id, + int dest_port_id, int dest_process_id) { + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + MessageChannel channel; - channel.port1 = source; - channel.port2 = dest; - channels_[GET_CHANNEL_ID(port1_id)] = channel; + channel.port1 = RenderProcessHost::FromID(source_process_id); + channel.port2 = RenderProcessHost::FromID(dest_process_id); + if (!channel.port1 || !channel.port2) { + // One of the processes could have been closed while posting this task. + return; + } + + channels_[GET_CHANNEL_ID(source_port_id)] = channel; + + std::string tab_json = "null"; + WebContents* contents = tab_util::GetWebContentsByID(source_process_id, + source_routing_id); + if (contents) { + DictionaryValue* tab_value = ExtensionTabUtil::CreateTabValue(contents); + JSONWriter::Write(tab_value, false, &tab_json); + } // Send each process the id for the opposite port. - dest->Send(new ViewMsg_ExtensionHandleConnect(port1_id)); - return port2_id; + channel.port2->Send(new ViewMsg_ExtensionHandleConnect(source_port_id, + tab_json)); } void ExtensionMessageService::PostMessageFromRenderer( - int port_id, const std::string& message, ResourceMessageFilter* source) { - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); + int port_id, const std::string& message) { + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); - // Look up the channel by port1's ID. MessageChannelMap::iterator iter = channels_.find(GET_CHANNEL_ID(port_id)); if (iter == channels_.end()) @@ -140,14 +186,8 @@ void ExtensionMessageService::PostMessageFromRenderer( MessageChannel& channel = iter->second; // 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); - } + RenderProcessHost* dest = + IS_PORT1_ID(port_id) ? channel.port1 : channel.port2; int source_port_id = GET_OPPOSITE_PORT_ID(port_id); dest->Send(new ViewMsg_ExtensionHandleMessage(message, source_port_id)); @@ -155,60 +195,38 @@ void ExtensionMessageService::PostMessageFromRenderer( void ExtensionMessageService::DispatchEventToRenderers( const std::string& event_name, const std::string& event_args) { - std::set<int> pids; - { - AutoLock lock(listener_lock_); - pids = listeners_[event_name]; - if (pids.empty()) - return; - } - MessageLoop* io_thread = ChromeThread::GetMessageLoop(ChromeThread::IO); - if (MessageLoop::current() != io_thread) { - // Do the actual work on the IO thread. - io_thread->PostTask(FROM_HERE, NewRunnableMethod(this, - &ExtensionMessageService::DispatchEventToRenderers, - event_name, event_args)); - return; - } + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + + std::set<int>& pids = listeners_[event_name]; // Send the event only to renderers that are listening for it. for (std::set<int>::iterator pid = pids.begin(); pid != pids.end(); ++pid) { - RendererMap::iterator renderer = renderers_.find(*pid); - if (renderer == renderers_.end()) + RenderProcessHost* renderer = RenderProcessHost::FromID(*pid); + if (!renderer) continue; - ResourceMessageFilter* filter = renderer->second; - filter->Send(new ViewMsg_ExtensionHandleEvent(event_name, event_args)); - } -} - -void ExtensionMessageService::RendererReady(ResourceMessageFilter* renderer) { - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); - - DCHECK(renderers_.find(renderer->GetProcessId()) == renderers_.end()); - renderers_[renderer->GetProcessId()] = renderer; - renderers_unique_.insert(renderer); - - if (!observing_renderer_shutdown_) { - observing_renderer_shutdown_ = true; - NotificationService::current()->AddObserver( - this, - NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN, - NotificationService::AllSources()); + renderer->Send(new ViewMsg_ExtensionHandleEvent(event_name, event_args)); } } void ExtensionMessageService::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); - DCHECK(type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN); - ResourceMessageFilter* renderer = Source<ResourceMessageFilter>(source).ptr(); + DCHECK(type.value == NotificationType::RENDERER_PROCESS_TERMINATED || + type.value == NotificationType::RENDERER_PROCESS_CRASHED); + RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); - renderers_.erase(renderer->GetProcessId()); - renderers_unique_.erase(renderer); + { + AutoLock lock(process_ids_lock_); + for (ProcessIDMap::iterator it = process_ids_.begin(); + it != process_ids_.end(); ) { + ProcessIDMap::iterator current = it++; + if (current->second == renderer->pid()) { + process_ids_.erase(current); + } + } + } // Close any channels that share this renderer. // TODO(mpcomplete): should we notify the other side of the port? diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h index 52b1682..343c632 100755 --- a/chrome/browser/extensions/extension_message_service.h +++ b/chrome/browser/extensions/extension_message_service.h @@ -12,8 +12,8 @@ #include "base/lock.h" #include "chrome/common/notification_observer.h" -class ExtensionView; -class ListValue; +class MessageLoop; +class RenderProcessHost; class ResourceMessageFilter; class URLRequestContext; @@ -44,33 +44,33 @@ class ExtensionMessageService : public NotificationObserver { void AddEventListener(std::string event_name, int render_process_id); void RemoveEventListener(std::string event_name, int render_process_id); - // --- IO thread only: - - // Given an extension's ID, opens a channel between the given renderer "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. - int OpenChannelToExtension(const std::string& extension_id, - ResourceMessageFilter* source); - // Sends a message from a renderer to the given port. - void PostMessageFromRenderer(int port_id, const std::string& message, - ResourceMessageFilter* source); + // TODO(mpcomplete): include the source tab. + void PostMessageFromRenderer(int port_id, const std::string& message); - // Called to let us know that a renderer has been started. - void RendererReady(ResourceMessageFilter* renderer); + // 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); - // --- UI or IO thread: + // --- IO thread only: - // Send an event to every registered extension renderer. - void DispatchEventToRenderers( - const std::string& event_name, const std::string& event_args); + // Given an extension's ID, opens a channel between the given renderer "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. + // This runs on the IO thread so that it can be used in a synchronous IPC + // message. + int OpenChannelToExtension(int routing_id, const std::string& extension_id, + ResourceMessageFilter* source); private: + // The UI message loop, used for posting tasks. + MessageLoop* ui_loop_; + // A map of extension ID to the render_process_id that the extension lives in. typedef std::map<std::string, int> ProcessIDMap; ProcessIDMap process_ids_; @@ -85,36 +85,35 @@ class ExtensionMessageService : public NotificationObserver { typedef std::map<std::string, std::set<int> > ListenerMap; ListenerMap listeners_; - // Protects listeners_ map, since it can be accessed from either the IO or - // UI thread. Be careful not to hold this lock when calling external code - // (especially sending messages) to avoid deadlock. - Lock listener_lock_; + // --- UI thread only: - // --- IO thread only: + // UI-thread specific initialization. Does nothing if called more than once. + void Init(); - // The connection between two renderers. + // Handles channel creation and notifies the destination that a channel was + // opened. + void OpenChannelOnUIThread(int source_routing_id, + int source_port_id, int source_process_id, + int dest_port_id, int dest_process_id); + + // The connection between two renderers. It is possible that both ports + // refer to the same renderer. struct MessageChannel { - ResourceMessageFilter* port1; - ResourceMessageFilter* port2; + RenderProcessHost* port1; + RenderProcessHost* port2; }; // A map of channel ID to its channel object. typedef std::map<int, MessageChannel> MessageChannelMap; MessageChannelMap channels_; - // For generating unique channel IDs. - int next_port_id_; - - // A map of render_process_id to its corresponding message filter, which we - // use for sending messages. - typedef std::map<int, ResourceMessageFilter*> RendererMap; - RendererMap renderers_; + // True if Init has been called. + bool initialized_; - // A unique list of renderers that we are aware of. - std::set<ResourceMessageFilter*> renderers_unique_; + // --- IO thread only: - // Set to true when we start observing this notification. - bool observing_renderer_shutdown_; + // For generating unique channel IDs. + int next_port_id_; DISALLOW_COPY_AND_ASSIGN(ExtensionMessageService); }; diff --git a/chrome/browser/extensions/extension_messages_unittest.cc b/chrome/browser/extensions/extension_messages_unittest.cc index 1ef9f43..606c301 100644 --- a/chrome/browser/extensions/extension_messages_unittest.cc +++ b/chrome/browser/extensions/extension_messages_unittest.cc @@ -59,7 +59,7 @@ TEST_F(RenderViewTest, ExtensionMessagesOnConnect) { ExecuteJavaScript( "chromium.self.onConnect.addListener(function (port) {" " port.onMessage.addListener(doOnMessage);" - " port.postMessage({message: 'onconnect'});" + " port.postMessage({message: 'onconnect from ' + port.tab.url});" "});" "function doOnMessage(msg, port) {" " alert('got: ' + msg.val);" @@ -69,7 +69,8 @@ TEST_F(RenderViewTest, ExtensionMessagesOnConnect) { // Simulate a new connection being opened. const int kPortId = 0; - RendererExtensionBindings::HandleConnect(kPortId); + RendererExtensionBindings::HandleConnect(kPortId, + "{\"url\":\"foo://bar\"}"); // Verify that we handled the new connection by posting a message. const IPC::Message* post_msg = @@ -78,7 +79,7 @@ TEST_F(RenderViewTest, ExtensionMessagesOnConnect) { ASSERT_TRUE(post_msg); ViewHostMsg_ExtensionPostMessage::Param post_params; ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params); - EXPECT_EQ("{\"message\":\"onconnect\"}", post_params.b); + EXPECT_EQ("{\"message\":\"onconnect from foo://bar\"}", post_params.b); // Now simulate getting a message back from the channel opener. render_thread_.sink().ClearMessages(); diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc index 069110e..41663dd 100644 --- a/chrome/browser/extensions/extension_tabs_module.cc +++ b/chrome/browser/extensions/extension_tabs_module.cc @@ -21,8 +21,6 @@ // Forward declare static helper functions defined below. static DictionaryValue* CreateWindowValue(Browser* browser); static ListValue* CreateTabList(Browser* browser); -static DictionaryValue* CreateTabValue(TabStripModel* tab_strip_model, - int tab_index); static bool GetIndexOfTabId(const TabStripModel* tab_strip, int tab_id, int* tab_index); @@ -39,6 +37,42 @@ int ExtensionTabUtil::GetWindowIdOfTab(const TabContents* tab_contents) { return tab_contents->controller().window_id().id(); } +DictionaryValue* ExtensionTabUtil::CreateTabValue( + const TabContents* contents) { + // Find the tab strip and index of this guy. + for (BrowserList::const_iterator it = BrowserList::begin(); + it != BrowserList::end(); ++it) { + TabStripModel* tab_strip = (*it)->tabstrip_model(); + int tab_index = tab_strip->GetIndexOfTabContents(contents); + if (tab_index != -1) { + return ExtensionTabUtil::CreateTabValue(contents, tab_strip, tab_index); + } + } + + // Couldn't find it. This can happen if the tab is being dragged. + return ExtensionTabUtil::CreateTabValue(contents, NULL, -1); +} + +DictionaryValue* ExtensionTabUtil::CreateTabValue( + const TabContents* contents, TabStripModel* tab_strip, int tab_index) { + DictionaryValue* result = new DictionaryValue(); + result->SetInteger(L"id", ExtensionTabUtil::GetTabId(contents)); + result->SetInteger(L"index", tab_index); + result->SetInteger(L"windowId", ExtensionTabUtil::GetWindowIdOfTab(contents)); + result->SetString(L"url", contents->GetURL().spec()); + result->SetString(L"title", UTF16ToWide(contents->GetTitle())); + result->SetBoolean(L"selected", + tab_strip && tab_index == tab_strip->selected_index()); + + NavigationEntry* entry = contents->controller().GetActiveEntry(); + if (entry) { + if (entry->favicon().is_valid()) + result->SetString(L"favIconUrl", entry->favicon().url().spec()); + } + + return result; +} + bool GetWindowsFunction::RunImpl() { std::set<int> window_ids; @@ -220,7 +254,7 @@ bool CreateTabFunction::RunImpl() { // Return data about the newly created tab. if (has_callback()) - result_.reset(CreateTabValue(tab_strip, index)); + result_.reset(ExtensionTabUtil::CreateTabValue(contents, tab_strip, index)); return true; } @@ -239,7 +273,8 @@ bool GetTabFunction::RunImpl() { if (!GetIndexOfTabId(tab_strip, tab_id, &tab_index)) return false; - result_.reset(CreateTabValue(tab_strip, tab_index)); + result_.reset(ExtensionTabUtil::CreateTabValue( + tab_strip->GetTabContentsAt(tab_index), tab_strip, tab_index)); return true; } @@ -366,33 +401,13 @@ static ListValue* CreateTabList(Browser* browser) { ListValue *tab_list = new ListValue(); TabStripModel* tab_strip = browser->tabstrip_model(); for (int i = 0; i < tab_strip->count(); ++i) { - tab_list->Append(CreateTabValue(tab_strip, i)); + tab_list->Append(ExtensionTabUtil::CreateTabValue( + tab_strip->GetTabContentsAt(i), tab_strip, i)); } return tab_list; } -static DictionaryValue* CreateTabValue(TabStripModel* tab_strip, - int tab_index) { - TabContents* contents = tab_strip->GetTabContentsAt(tab_index); - - DictionaryValue* result = new DictionaryValue(); - result->SetInteger(L"id", ExtensionTabUtil::GetTabId(contents)); - result->SetInteger(L"index", tab_index); - result->SetInteger(L"windowId", ExtensionTabUtil::GetWindowIdOfTab(contents)); - result->SetString(L"url", contents->GetURL().spec()); - result->SetString(L"title", UTF16ToWide(contents->GetTitle())); - result->SetBoolean(L"selected", tab_index == tab_strip->selected_index()); - - NavigationEntry* entry = contents->controller().GetActiveEntry(); - if (entry) { - if (entry->favicon().is_valid()) - result->SetString(L"favIconUrl", entry->favicon().url().spec()); - } - - return result; -} - static bool GetIndexOfTabId(const TabStripModel* tab_strip, int tab_id, int* tab_index) { for (int i = 0; i < tab_strip->count(); ++i) { diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h index 90c8647..c139f6a 100644 --- a/chrome/browser/extensions/extension_tabs_module.h +++ b/chrome/browser/extensions/extension_tabs_module.h @@ -8,13 +8,18 @@ #include "chrome/browser/extensions/extension_function.h" class Browser; +class DictionaryValue; class TabContents; +class TabStripModel; class ExtensionTabUtil { public: static int GetWindowId(const Browser* browser); static int GetTabId(const TabContents* tab_contents); static int GetWindowIdOfTab(const TabContents* tab_contents); + static DictionaryValue* CreateTabValue(const TabContents* tab_contents); + static DictionaryValue* CreateTabValue( + const TabContents* tab_contents, TabStripModel* tab_strip, int tab_index); }; class GetWindowsFunction : public SyncExtensionFunction { diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 3646358..c3d7aeb 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -15,8 +15,9 @@ #include "chrome/browser/cross_site_request_manager.h" #include "chrome/browser/debugger/debugger_wrapper.h" #include "chrome/browser/debugger/devtools_manager.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/renderer_security_policy.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" @@ -26,13 +27,13 @@ #include "chrome/browser/tab_contents/site_instance.h" #include "chrome/browser/tab_contents/web_contents.h" #include "chrome/common/bindings_policy.h" -#include "chrome/common/render_messages.h" -#include "chrome/common/resource_bundle.h" #include "chrome/common/notification_service.h" #include "chrome/common/notification_type.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/resource_bundle.h" #include "chrome/common/result_codes.h" -#include "chrome/common/url_constants.h" #include "chrome/common/thumbnail_score.h" +#include "chrome/common/url_constants.h" #include "net/base/net_util.h" #include "skia/include/SkBitmap.h" #include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h" @@ -775,6 +776,8 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_SelectionChanged, OnMsgSelectionChanged) IPC_MESSAGE_HANDLER(ViewHostMsg_PasteFromSelectionClipboard, OnMsgPasteFromSelectionClipboard) + IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionPostMessage, + OnExtensionPostMessage) // Have the super handle all other messages. IPC_MESSAGE_UNHANDLED(RenderWidgetHost::OnMessageReceived(msg)) IPC_END_MESSAGE_MAP_EX() @@ -1368,3 +1371,10 @@ void RenderViewHost::SendExtensionResponse(int callback_id, const std::string& response) { Send(new ViewMsg_ExtensionResponse(routing_id(), callback_id, response)); } + +void RenderViewHost::OnExtensionPostMessage( + int port_id, const std::string& message) { + URLRequestContext* context = process()->profile()->GetRequestContext(); + ExtensionMessageService::GetInstance(context)-> + PostMessageFromRenderer(port_id, message); +} diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 0125b50..b86b5f5 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -543,6 +543,7 @@ class RenderViewHost : public RenderWidgetHost { void OnExtensionRequest(const std::string& name, const std::string& args, int callback_id); + void OnExtensionPostMessage(int port_id, const std::string& message); // Helper function to send a navigation message. If a cross-site request is // in progress, we may be suspended while waiting for the onbeforeunload diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 804042f..3fc0602 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -193,10 +193,6 @@ void ResourceMessageFilter::OnChannelConnected(int32 peer_pid) { // Hook AudioRendererHost to this object after channel is connected so it can // this object for sending messages. audio_renderer_host_->IPCChannelConnected(render_process_id_, handle(), this); - - // Ditto for the ExtensionMessageService. - ExtensionMessageService::GetInstance(request_context_.get())-> - RendererReady(this); } // Called on the IPC thread: @@ -299,8 +295,6 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { #endif IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToExtension, OnOpenChannelToExtension) - IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionPostMessage, - OnExtensionPostMessage) IPC_MESSAGE_UNHANDLED( handled = false) IPC_END_MESSAGE_MAP_EX() @@ -829,13 +823,7 @@ void ResourceMessageFilter::OnFreeTransportDIB( #endif void ResourceMessageFilter::OnOpenChannelToExtension( - const std::string& extension_id, int* port_id) { + int routing_id, const std::string& extension_id, int* port_id) { *port_id = ExtensionMessageService::GetInstance(request_context_.get())-> - OpenChannelToExtension(extension_id, this); -} - -void ResourceMessageFilter::OnExtensionPostMessage( - int port_id, const std::string& message) { - ExtensionMessageService::GetInstance(request_context_.get())-> - PostMessageFromRenderer(port_id, message, this); + OpenChannelToExtension(routing_id, extension_id, this); } diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 74181bf..e16ac8d 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -202,8 +202,8 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, TransportDIB::Handle* result); void OnFreeTransportDIB(TransportDIB::Id dib_id); - void OnOpenChannelToExtension(const std::string& extension_id, int* port_id); - void OnExtensionPostMessage(int port_id, const std::string& message); + void OnOpenChannelToExtension(int routing_id, + const std::string& extension_id, int* port_id); #if defined(OS_LINUX) void SendDelayedReply(IPC::Message* reply_msg); diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 60f250e..3279f60 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1589,6 +1589,7 @@ # short term I'd like the build to work. 'renderer/automation/dom_automation_controller.cc', 'renderer/automation/dom_automation_controller.h', + 'renderer/extensions/bindings_utils.cc', 'renderer/extensions/bindings_utils.h', 'renderer/extensions/event_bindings.cc', 'renderer/extensions/event_bindings.h', diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 66f64b4..776fd44d 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -535,9 +535,11 @@ IPC_BEGIN_MESSAGES(View) // Tell the extension process about a new channel that has been opened from a // renderer. source_port_id identifies the port that the extension can - // respond to. - IPC_MESSAGE_CONTROL1(ViewMsg_ExtensionHandleConnect, - int /* source_port_id */) + // respond to. tab_json is a JSON value for the tab that opened the + // connection, if any. + IPC_MESSAGE_CONTROL2(ViewMsg_ExtensionHandleConnect, + int /* source_port_id */, + std::string /* tab_json */) // Send a javascript message to a renderer from the given port. IPC_MESSAGE_CONTROL2(ViewMsg_ExtensionHandleMessage, @@ -1339,15 +1341,16 @@ IPC_BEGIN_MESSAGES(ViewHost) // Get a port handle to a currently-running extension process for the // extension with the given ID. If no such extension is found, -1 is // returned. The handle can be used for sending messages to the extension. - IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_OpenChannelToExtension, + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_OpenChannelToExtension, + int /* routing_id */, std::string /* extension_id */, int /* port_id */) // Send a message to an extension process. The handle is the value returned // by ViewHostMsg_OpenChannelToExtension. - IPC_MESSAGE_CONTROL2(ViewHostMsg_ExtensionPostMessage, - int /* port_id */, - std::string /* message */) + IPC_MESSAGE_ROUTED2(ViewHostMsg_ExtensionPostMessage, + int /* port_id */, + std::string /* message */) // Message to show a popup menu using native cocoa controls (Mac only). IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowPopup, diff --git a/chrome/renderer/extensions/bindings_utils.cc b/chrome/renderer/extensions/bindings_utils.cc new file mode 100644 index 0000000..ee4688d --- /dev/null +++ b/chrome/renderer/extensions/bindings_utils.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/extensions/bindings_utils.h" + +#include "chrome/renderer/render_view.h" +#include "webkit/glue/webframe.h" + +RenderView* GetActiveRenderView() { + WebFrame* webframe = WebFrame::RetrieveActiveFrame(); + DCHECK(webframe) << "GetActiveRenderView called when not in a V8 context."; + if (!webframe) + return NULL; + + WebView* webview = webframe->GetView(); + if (!webview) + return NULL; // can happen during closing + + RenderView* renderview = static_cast<RenderView*>(webview->GetDelegate()); + DCHECK(renderview) << "Encountered a WebView without a WebViewDelegate"; + return renderview; +} diff --git a/chrome/renderer/extensions/bindings_utils.h b/chrome/renderer/extensions/bindings_utils.h index 9e7d213..84fb32f 100755 --- a/chrome/renderer/extensions/bindings_utils.h +++ b/chrome/renderer/extensions/bindings_utils.h @@ -10,6 +10,8 @@ #include <string> +class RenderView; + template<int kResourceId> struct StringResourceTemplate { StringResourceTemplate() @@ -25,4 +27,8 @@ const char* GetStringResource() { Singleton< StringResourceTemplate<kResourceId> >::get()->resource.c_str(); } +// Returns the active RenderView, based on which V8 context is active. It is +// an error to call this when not in a V8 context. +RenderView* GetActiveRenderView(); + #endif // CHROME_RENDERER_EXTENSIONS_BINDINGS_UTILS_H_ diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc index fcf9710..1c1ac79 100644 --- a/chrome/renderer/extensions/extension_process_bindings.cc +++ b/chrome/renderer/extensions/extension_process_bindings.cc @@ -70,16 +70,9 @@ class ExtensionImpl : public v8::Extension { static v8::Handle<v8::Value> StartRequest(const v8::Arguments& args) { WebFrame* webframe = WebFrame::RetrieveActiveFrame(); - DCHECK(webframe) << "There should be an active frame since we just got " - "a native function called."; - if (!webframe) return v8::Undefined(); - - WebView* webview = webframe->GetView(); - if (!webview) return v8::Undefined(); // can happen during closing - - RenderView* renderview = static_cast<RenderView*>(webview->GetDelegate()); - DCHECK(renderview) << "Encountered a WebView without a WebViewDelegate"; - if (!renderview) return v8::Undefined(); + RenderView* renderview = GetActiveRenderView(); + if (!webframe || !renderview) + return v8::Undefined(); if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsInt32()) return v8::Undefined(); diff --git a/chrome/renderer/extensions/renderer_extension_bindings.cc b/chrome/renderer/extensions/renderer_extension_bindings.cc index 63214d73..28b5c47 100755 --- a/chrome/renderer/extensions/renderer_extension_bindings.cc +++ b/chrome/renderer/extensions/renderer_extension_bindings.cc @@ -10,6 +10,7 @@ #include "chrome/renderer/extensions/bindings_utils.h" #include "chrome/renderer/extensions/event_bindings.h" #include "chrome/renderer/render_thread.h" +#include "chrome/renderer/render_view.h" #include "grit/renderer_resources.h" // Message passing API example (in a content script): @@ -24,9 +25,6 @@ namespace { -// We use the generic interface so that unit tests can inject a mock. -RenderThreadBase* render_thread_ = NULL; - const char* kExtensionDeps[] = { EventBindings::kName }; class ExtensionImpl : public v8::Extension { @@ -51,11 +49,15 @@ class ExtensionImpl : public v8::Extension { // Creates a new messaging channel to the given extension. static v8::Handle<v8::Value> OpenChannelToExtension( const v8::Arguments& args) { + RenderView* renderview = GetActiveRenderView(); + if (!renderview) + return v8::Undefined(); + if (args.Length() >= 1 && args[0]->IsString()) { std::string id = *v8::String::Utf8Value(args[0]->ToString()); int port_id = -1; - render_thread_->Send( - new ViewHostMsg_OpenChannelToExtension(id, &port_id)); + renderview->Send(new ViewHostMsg_OpenChannelToExtension( + renderview->routing_id(), id, &port_id)); return v8::Integer::New(port_id); } return v8::Undefined(); @@ -63,11 +65,15 @@ class ExtensionImpl : public v8::Extension { // Sends a message along the given channel. static v8::Handle<v8::Value> PostMessage(const v8::Arguments& args) { + RenderView* renderview = GetActiveRenderView(); + if (!renderview) + return v8::Undefined(); + if (args.Length() >= 2 && args[0]->IsInt32() && args[1]->IsString()) { int port_id = args[0]->Int32Value(); std::string message = *v8::String::Utf8Value(args[1]->ToString()); - render_thread_->Send( - new ViewHostMsg_ExtensionPostMessage(port_id, message)); + renderview->Send(new ViewHostMsg_ExtensionPostMessage( + renderview->routing_id(), port_id, message)); } return v8::Undefined(); } @@ -78,15 +84,16 @@ class ExtensionImpl : public v8::Extension { const char* RendererExtensionBindings::kName = "chrome/RendererExtensionBindings"; -v8::Extension* RendererExtensionBindings::Get(RenderThreadBase* render_thread) { - render_thread_ = render_thread; +v8::Extension* RendererExtensionBindings::Get() { return new ExtensionImpl(); } -void RendererExtensionBindings::HandleConnect(int port_id) { +void RendererExtensionBindings::HandleConnect(int port_id, + const std::string& tab_json) { v8::HandleScope handle_scope; - v8::Handle<v8::Value> argv[1]; + v8::Handle<v8::Value> argv[2]; argv[0] = v8::Integer::New(port_id); + argv[1] = v8::String::New(tab_json.c_str()); EventBindings::CallFunction("chromium.Port.dispatchOnConnect_", arraysize(argv), argv); } diff --git a/chrome/renderer/extensions/renderer_extension_bindings.h b/chrome/renderer/extensions/renderer_extension_bindings.h index 374dfb6..ad370af 100755 --- a/chrome/renderer/extensions/renderer_extension_bindings.h +++ b/chrome/renderer/extensions/renderer_extension_bindings.h @@ -19,11 +19,12 @@ class RendererExtensionBindings { static const char* kName; // Creates an instance of the extension. - static v8::Extension* Get(RenderThreadBase* render_thread); + static v8::Extension* Get(); // Notify any listeners that a message channel has been opened to this - // process. - static void HandleConnect(int port_id); + // process. |tab_json| is the info for the tab that initiated this + // connection, or "null" if the initiator was not a tab. + static void HandleConnect(int port_id, const std::string& tab_json); // Dispatch the given message sent on this channel. static void HandleMessage(const std::string& message, int port_id); diff --git a/chrome/renderer/mock_render_thread.cc b/chrome/renderer/mock_render_thread.cc index b133238..7812b31 100644 --- a/chrome/renderer/mock_render_thread.cc +++ b/chrome/renderer/mock_render_thread.cc @@ -92,7 +92,7 @@ void MockRenderThread::OnMsgCreateWidget(int opener_id, } void MockRenderThread::OnMsgOpenChannelToExtension( - const std::string& extension_id, int* channel_id) { + int routing_id, const std::string& extension_id, int* channel_id) { *channel_id = 0; } diff --git a/chrome/renderer/mock_render_thread.h b/chrome/renderer/mock_render_thread.h index f88543b..e4f2403 100644 --- a/chrome/renderer/mock_render_thread.h +++ b/chrome/renderer/mock_render_thread.h @@ -74,7 +74,8 @@ class MockRenderThread : public RenderThreadBase { int* route_id); // The callee expects to be returned a valid channel_id. - void OnMsgOpenChannelToExtension(const std::string& extension_id, + void OnMsgOpenChannelToExtension(int routing_id, + const std::string& extension_id, int* channel_id); // The RenderView expects default print settings. diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index 26836ca..afe3f38 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -314,7 +314,7 @@ void RenderThread::EnsureWebKitInitialized() { WebKit::registerExtension(JsonJsV8Extension::Get()); WebKit::registerExtension(JsonSchemaJsV8Extension::Get()); WebKit::registerExtension(EventBindings::Get()); - WebKit::registerExtension(RendererExtensionBindings::Get(this)); + WebKit::registerExtension(RendererExtensionBindings::Get()); } if (command_line.HasSwitch(switches::kPlaybackMode) || @@ -328,8 +328,9 @@ void RenderThread::EnsureWebKitInitialized() { } } -void RenderThread::OnExtensionHandleConnect(int port_id) { - RendererExtensionBindings::HandleConnect(port_id); +void RenderThread::OnExtensionHandleConnect(int port_id, + const std::string& tab_json) { + RendererExtensionBindings::HandleConnect(port_id, tab_json); } void RenderThread::OnExtensionHandleMessage(const std::string& message, diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h index d50fd96..24b4574 100644 --- a/chrome/renderer/render_thread.h +++ b/chrome/renderer/render_thread.h @@ -127,7 +127,7 @@ class RenderThread : public RenderThreadBase, // Send all histograms to browser. void OnGetRendererHistograms(); - void OnExtensionHandleConnect(int channel_id); + void OnExtensionHandleConnect(int channel_id, const std::string& tab_json); void OnExtensionHandleMessage(const std::string& message, int channel_id); void OnExtensionHandleEvent(const std::string event_name, const std::string event_data); diff --git a/chrome/renderer/renderer.vcproj b/chrome/renderer/renderer.vcproj index d0c9de4..249f133 100644 --- a/chrome/renderer/renderer.vcproj +++ b/chrome/renderer/renderer.vcproj @@ -193,6 +193,10 @@ Name="extensions" > <File + RelativePath=".\extensions\bindings_utils.cc" + > + </File> + <File RelativePath=".\extensions\bindings_utils.h" > </File> diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd index c59e98c..beb23b7 100755 --- a/chrome/renderer/renderer_resources.grd +++ b/chrome/renderer/renderer_resources.grd @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- This comment is only here because changes to resources are not picked up -without changes to the corresponding grd file. --> +without changes to the corresponding grd file. 1 --> <grit latest_public_release="0" current_release="1"> <outputs> <output filename="grit/renderer_resources.h" type="rc_header"> diff --git a/chrome/renderer/resources/renderer_extension_bindings.js b/chrome/renderer/resources/renderer_extension_bindings.js index 19518db..11494e3 100644 --- a/chrome/renderer/resources/renderer_extension_bindings.js +++ b/chrome/renderer/resources/renderer_extension_bindings.js @@ -30,8 +30,12 @@ var chromium = chromium || {}; chromium.Port.ports_ = {}; // Called by native code when a channel has been opened to this context. - chromium.Port.dispatchOnConnect_ = function(portId) { + chromium.Port.dispatchOnConnect_ = function(portId, tab) { var port = new chromium.Port(portId); + if (tab) { + tab = goog.json.parse(tab); + } + port.tab = tab; chromium.Event.dispatch_("channel-connect", [port]); }; diff --git a/chrome/test/data/extensions/good/extension1/1/toolstrip1.html b/chrome/test/data/extensions/good/extension1/1/toolstrip1.html index fa244f8..d36de21 100644 --- a/chrome/test/data/extensions/good/extension1/1/toolstrip1.html +++ b/chrome/test/data/extensions/good/extension1/1/toolstrip1.html @@ -22,7 +22,7 @@ body { chromium.onconnect.addListener(function (port) { port.onmessage.addListener(doOnMessage); - port.postMessage('extension onconnect'); + port.postMessage('extension onconnect: ' + port.tab.url); }); function doOnMessage(msg, port) { diff --git a/chrome/test/render_view_test.cc b/chrome/test/render_view_test.cc index 81d7347..583fff6 100644 --- a/chrome/test/render_view_test.cc +++ b/chrome/test/render_view_test.cc @@ -58,7 +58,7 @@ void RenderViewTest::SetUp() { WebKit::registerExtension(JsonSchemaJsV8Extension::Get()); WebKit::registerExtension(EventBindings::Get()); WebKit::registerExtension(ExtensionProcessBindings::Get()); - WebKit::registerExtension(RendererExtensionBindings::Get(&render_thread_)); + WebKit::registerExtension(RendererExtensionBindings::Get()); EventBindings::SetRenderThread(&render_thread_); // TODO(aa): Should some of this go to some other inheriting class? |