diff options
author | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-23 22:21:43 +0000 |
---|---|---|
committer | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-23 22:21:43 +0000 |
commit | 0aa477bd3cd906e880891fd2e9f4739a53270a7f (patch) | |
tree | f78ab46e2bd5aca2812755d3240fd8cf4e83c8f5 /chrome/browser/extensions | |
parent | 1d437b64e1aaf11827962de62694bcb806265d00 (diff) | |
download | chromium_src-0aa477bd3cd906e880891fd2e9f4739a53270a7f.zip chromium_src-0aa477bd3cd906e880891fd2e9f4739a53270a7f.tar.gz chromium_src-0aa477bd3cd906e880891fd2e9f4739a53270a7f.tar.bz2 |
Initial rev at a message passing API for extensions. So far, only passing
messages to the extension process is supported.
Review URL: http://codereview.chromium.org/48090
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12319 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rwxr-xr-x | chrome/browser/extensions/extension_message_service.cc | 133 | ||||
-rwxr-xr-x | chrome/browser/extensions/extension_message_service.h | 73 | ||||
-rwxr-xr-x | chrome/browser/extensions/extension_view.cc | 11 | ||||
-rwxr-xr-x | chrome/browser/extensions/extension_view.h | 9 | ||||
-rwxr-xr-x | chrome/browser/extensions/extension_view_unittest.cc | 6 |
5 files changed, 226 insertions, 6 deletions
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc new file mode 100755 index 0000000..7b79c9e --- /dev/null +++ b/chrome/browser/extensions/extension_message_service.cc @@ -0,0 +1,133 @@ +// 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/browser/extensions/extension_message_service.h" + +#include "base/singleton.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/extensions/extension.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/common/render_messages.h" + +// This class acts as the port to an extension process. It is basically just +// gymnastics to get access to the IPC::Channel (not the ChannelProxy) belonging +// to an ExtensionView. +// Created on the UI thread, but accessed fully on the IO thread. +class ExtensionMessageService::ExtensionFilter : + public IPC::ChannelProxy::MessageFilter { + public: + ExtensionFilter(const std::string& extension_id, int routing_id) : + extension_id_(extension_id), routing_id_(routing_id), channel_(NULL) { + } + ~ExtensionFilter() { + ExtensionMessageService::GetInstance()->OnExtensionUnregistered(this); + } + + virtual void OnFilterAdded(IPC::Channel* channel) { + channel_ = channel; + ExtensionMessageService::GetInstance()->OnExtensionRegistered(this); + } + virtual void OnChannelClosing() { + channel_ = NULL; + } + + bool Send(IPC::Message* message) { + if (!channel_) { + delete message; + return false; + } + return channel_->Send(message); + } + + IPC::Channel* channel() { return channel_; } + const std::string& extension_id() { return extension_id_; } + int routing_id() { return routing_id_; } + + private: + std::string extension_id_; + int routing_id_; + IPC::Channel* channel_; +}; + +ExtensionMessageService* ExtensionMessageService::GetInstance() { + return Singleton<ExtensionMessageService>::get(); +} + +ExtensionMessageService::ExtensionMessageService() + : next_channel_id_(0) { +} + +void ExtensionMessageService::RegisterExtensionView(ExtensionView* view) { + view->render_view_host()->process()->channel()->AddFilter( + new ExtensionFilter(view->extension()->id(), + view->render_view_host()->routing_id())); +} + +void ExtensionMessageService::OnExtensionRegistered(ExtensionFilter* filter) { + extensions_[filter->extension_id()] = filter; +} + +void ExtensionMessageService::OnExtensionUnregistered(ExtensionFilter* filter) { + // TODO(mpcomplete): support multiple filters per extension_id + //DCHECK(extensions_[filter->extension_id()] == filter); + extensions_.erase(filter->extension_id()); + + // Close any channels that share this filter. + for (MessageChannelMap::iterator it = channels_.begin(); + it != channels_.end(); ) { + MessageChannelMap::iterator current = it++; + if (current->second.extension_port == filter) + channels_.erase(current); + } +} + +int ExtensionMessageService::OpenChannelToExtension( + const std::string& extension_id, ResourceMessageFilter* renderer_port) { + DCHECK(MessageLoop::current() == + ChromeThread::GetMessageLoop(ChromeThread::IO)); + + ExtensionMap::iterator extension_port = extensions_.find(extension_id); + if (extension_port == extensions_.end()) + return -1; + + int channel_id = next_channel_id_++; + MessageChannel channel; + channel.renderer_port = renderer_port; + channel.extension_port = extension_port->second; + channels_[channel_id] = channel; + + return channel_id; +} + +void ExtensionMessageService::PostMessage( + int channel_id, const std::string& message) { + DCHECK(MessageLoop::current() == + ChromeThread::GetMessageLoop(ChromeThread::IO)); + + MessageChannelMap::iterator iter = channels_.find(channel_id); + if (iter == channels_.end()) + return; + + MessageChannel& channel = iter->second; + channel.extension_port->Send(new ViewMsg_HandleExtensionMessage( + channel.extension_port->routing_id(), message, channel_id)); +} + +void ExtensionMessageService::RendererShutdown( + ResourceMessageFilter* renderer_port) { + DCHECK(MessageLoop::current() == + ChromeThread::GetMessageLoop(ChromeThread::IO)); + + // Close any channels that share this filter. + // TODO(mpcomplete): should we notify the other side of the port? + for (MessageChannelMap::iterator it = channels_.begin(); + it != channels_.end(); ) { + MessageChannelMap::iterator current = it++; + if (current->second.renderer_port == renderer_port) + channels_.erase(current); + } +} diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h new file mode 100755 index 0000000..eef1676 --- /dev/null +++ b/chrome/browser/extensions/extension_message_service.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_SERVICE_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_SERVICE_H_ + +#include <map> +#include <string> + +class ExtensionView; +class ResourceMessageFilter; + +// This class manages message passing to and from extension processes. It +// maintains a list of available extensions, as well as a set of open channels. +// It should only be accessed on the IO thread, with the exception of +// RegisterExtensionView(). +// +// Terminology: +// channel: connection between two ports (one of which belongs to an extension) +// port: an IPC::Message::Sender interface through which we communicate to a +// process. We use MessageFilters for this since that allows us to send our +// messages on the IO thread. +class ExtensionMessageService { + public: + static ExtensionMessageService* GetInstance(); + + ExtensionMessageService(); + + // Registers an extension so that it can be referenced by its ID. This method + // should only be used by the UI thread. + void RegisterExtensionView(ExtensionView* view); + + // 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* renderer_port); + + // Sends a message to the extension via the given channel. + void PostMessage(int channel_id, const std::string& message); + + // Called to let us know that a renderer is going away. + void RendererShutdown(ResourceMessageFilter* renderer_port); + private: + class ExtensionFilter; + friend class ExtensionFilter; + + // Called when our ExtensionFilter is ready/going away. + void OnExtensionRegistered(ExtensionFilter* extension); + void OnExtensionUnregistered(ExtensionFilter* extension); + + // A map of extension ID to the extension port to communicate through. + // TODO(mpcomplete): Handle the case where there's multiple ExtensionViews + // in a given extension. + typedef std::map<std::string, ExtensionFilter*> ExtensionMap; + ExtensionMap extensions_; + + // The connection between the renderer and extension. + struct MessageChannel { + ExtensionFilter* extension_port; + ResourceMessageFilter* renderer_port; + }; + + // A map of channel ID to its channel object. + typedef std::map<int, MessageChannel> MessageChannelMap; + MessageChannelMap channels_; + + // For generating unique channel IDs. + int next_channel_id_; +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_SERVICE_H_ diff --git a/chrome/browser/extensions/extension_view.cc b/chrome/browser/extensions/extension_view.cc index 6cd9c97b..0ceb7e4 100755 --- a/chrome/browser/extensions/extension_view.cc +++ b/chrome/browser/extensions/extension_view.cc @@ -4,10 +4,13 @@ #include "chrome/browser/extensions/extension_view.h" +#include "chrome/browser/extensions/extension.h" +#include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/renderer_host/render_view_host.h" -ExtensionView::ExtensionView(const GURL& url, Profile* profile) : - HWNDHtmlView(url, this, false), profile_(profile) { +ExtensionView::ExtensionView( + Extension* extension, const GURL& url, Profile* profile) : + HWNDHtmlView(url, this, false), extension_(extension), profile_(profile) { // TODO(mpcomplete): query this from the renderer somehow? set_preferred_size(gfx::Size(100, 100)); } @@ -16,6 +19,10 @@ void ExtensionView::CreatingRenderer() { render_view_host()->AllowExtensionBindings(); } +void ExtensionView::RenderViewCreated(RenderViewHost* render_view_host) { + ExtensionMessageService::GetInstance()->RegisterExtensionView(this); +} + WebPreferences ExtensionView::GetWebkitPrefs() { // TODO(mpcomplete): return some reasonable prefs. return WebPreferences(); diff --git a/chrome/browser/extensions/extension_view.h b/chrome/browser/extensions/extension_view.h index 6bb9e7a5..3ae3c23 100755 --- a/chrome/browser/extensions/extension_view.h +++ b/chrome/browser/extensions/extension_view.h @@ -14,6 +14,7 @@ #include "chrome/common/temp_scaffolding_stubs.h" #endif +class Extension; class Profile; struct WebPreferences; @@ -24,13 +25,14 @@ struct WebPreferences; class ExtensionView : public HWNDHtmlView, public RenderViewHostDelegate { public: - ExtensionView(const GURL& url, Profile* profile); + ExtensionView(Extension* extension, const GURL& url, Profile* profile); // HWNDHtmlView virtual void CreatingRenderer(); // RenderViewHostDelegate virtual Profile* GetProfile() const { return profile_; } + virtual void RenderViewCreated(RenderViewHost* render_view_host); virtual WebPreferences GetWebkitPrefs(); virtual void RunJavaScriptMessage( const std::wstring& message, @@ -40,7 +42,12 @@ class ExtensionView : public HWNDHtmlView, IPC::Message* reply_msg, bool* did_suppress_message); + Extension* extension() { return extension_; } private: + // The extension that we're hosting in this view. + Extension* extension_; + + // The profile that owns this extension. Profile* profile_; DISALLOW_COPY_AND_ASSIGN(ExtensionView); diff --git a/chrome/browser/extensions/extension_view_unittest.cc b/chrome/browser/extensions/extension_view_unittest.cc index c23cdf7..bc17d4c 100755 --- a/chrome/browser/extensions/extension_view_unittest.cc +++ b/chrome/browser/extensions/extension_view_unittest.cc @@ -30,8 +30,8 @@ const char* kExtensionId = "00123456789abcdef0123456789abcdef0123456"; // up a javascript alert. class MockExtensionView : public ExtensionView { public: - MockExtensionView(const GURL& url, Profile* profile) - : ExtensionView(url, profile), got_message_(false) { + MockExtensionView(Extension* extension, const GURL& url, Profile* profile) + : ExtensionView(extension, url, profile), got_message_(false) { InitHidden(); MessageLoop::current()->PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, kAlertTimeoutMs); @@ -136,6 +136,6 @@ IN_PROC_BROWSER_TEST_F(ExtensionViewTest, Index) { GURL url = Extension::GetResourceURL(extension->url(), "toolstrip1.html"); // Start the extension process and wait for it to show a javascript alert. - MockExtensionView view(url, profile); + MockExtensionView view(extension, url, profile); EXPECT_TRUE(view.got_message()); } |