summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
authormpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-23 22:21:43 +0000
committermpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-23 22:21:43 +0000
commit0aa477bd3cd906e880891fd2e9f4739a53270a7f (patch)
treef78ab46e2bd5aca2812755d3240fd8cf4e83c8f5 /chrome/browser/extensions
parent1d437b64e1aaf11827962de62694bcb806265d00 (diff)
downloadchromium_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-xchrome/browser/extensions/extension_message_service.cc133
-rwxr-xr-xchrome/browser/extensions/extension_message_service.h73
-rwxr-xr-xchrome/browser/extensions/extension_view.cc11
-rwxr-xr-xchrome/browser/extensions/extension_view.h9
-rwxr-xr-xchrome/browser/extensions/extension_view_unittest.cc6
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());
}