summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-11 22:07:08 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-11 22:07:08 +0000
commit41999c790950781a3598bad03b6179d685e9d82a (patch)
treeae629d8bb881848b3c71eed3f5d458780d655085
parent85d85890e689af734e46660b561fcfc2b69f993f (diff)
downloadchromium_src-41999c790950781a3598bad03b6179d685e9d82a.zip
chromium_src-41999c790950781a3598bad03b6179d685e9d82a.tar.gz
chromium_src-41999c790950781a3598bad03b6179d685e9d82a.tar.bz2
Revert "Revert "Looks like this introduced leaks in sync ui tests. Sigh.""
This reverts commit cb8e078c2e7bebf0604871ec0bda69ceac3734d2. TBR=mpcomplete@chromium.org git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85058 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chrome_content_browser_client.cc83
-rw-r--r--chrome/browser/chrome_content_browser_client.h3
-rw-r--r--chrome/browser/extensions/extension_bookmark_manager_api.cc19
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module.cc2
-rw-r--r--chrome/browser/extensions/extension_file_browser_private_api.cc13
-rw-r--r--chrome/browser/extensions/extension_function.cc56
-rw-r--r--chrome/browser/extensions/extension_function.h42
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc178
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.h71
-rw-r--r--chrome/browser/extensions/extension_host.cc64
-rw-r--r--chrome/browser/extensions/extension_host.h5
-rw-r--r--chrome/browser/extensions/extension_tab_helper.cc46
-rw-r--r--chrome/browser/extensions/extension_tab_helper.h12
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc2
-rw-r--r--chrome/browser/extensions/extension_web_ui.cc72
-rw-r--r--chrome/browser/extensions/extension_web_ui.h31
-rw-r--r--chrome/browser/extensions/extension_webstore_private_api.cc4
-rw-r--r--chrome/browser/extensions/extensions_ui.cc18
-rw-r--r--chrome/browser/memory_details.cc4
-rw-r--r--chrome/browser/notifications/balloon_host.cc57
-rw-r--r--chrome/browser/notifications/balloon_host.h11
-rw-r--r--chrome/browser/sidebar/sidebar_container.cc14
-rw-r--r--chrome/browser/ui/webui/options/extension_settings_handler.cc18
-rw-r--r--chrome/browser/visitedlink/visitedlink_unittest.cc4
-rw-r--r--chrome/renderer/extensions/extension_dispatcher.cc29
-rw-r--r--chrome/renderer/extensions/extension_dispatcher.h8
-rw-r--r--content/browser/content_browser_client.cc5
-rw-r--r--content/browser/content_browser_client.h9
-rw-r--r--content/browser/renderer_host/browser_render_process_host.cc29
-rw-r--r--content/browser/renderer_host/browser_render_process_host.h8
-rw-r--r--content/browser/renderer_host/mock_render_process_host.cc5
-rw-r--r--content/browser/renderer_host/mock_render_process_host.h2
-rw-r--r--content/browser/renderer_host/render_process_host.cc1
-rw-r--r--content/browser/renderer_host/render_process_host.h10
-rw-r--r--content/browser/renderer_host/render_view_host.cc12
-rw-r--r--content/browser/renderer_host/render_view_host.h10
-rw-r--r--content/browser/tab_contents/render_view_host_manager.cc5
-rw-r--r--content/common/notification_type.h16
38 files changed, 518 insertions, 460 deletions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 8efed98..b7ce694 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -26,19 +26,13 @@
#include "chrome/browser/ui/webui/chrome_web_ui_factory.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "content/browser/browsing_instance.h"
-#include "content/browser/child_process_security_policy.h"
#include "content/browser/renderer_host/browser_render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/renderer_host/render_view_host_notification_task.h"
#include "content/browser/resource_context.h"
-#include "content/browser/site_instance.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/worker_host/worker_process_host.h"
-#include "content/common/bindings_policy.h"
#include "net/base/cookie_monster.h"
#include "net/base/cookie_options.h"
#include "net/base/static_cookie_policy.h"
@@ -48,65 +42,6 @@
#include "chrome/browser/crash_handler_host_linux.h"
#endif // OS_LINUX
-namespace {
-
-void InitRenderViewHostForExtensions(RenderViewHost* render_view_host) {
- // Note that due to GetEffectiveURL(), even hosted apps will have a
- // chrome-extension:// URL for their site, so we can ignore that wrinkle here.
- SiteInstance* site_instance = render_view_host->site_instance();
- const GURL& site = site_instance->site();
- RenderProcessHost* process = render_view_host->process();
-
- if (!site.SchemeIs(chrome::kExtensionScheme))
- return;
-
- Profile* profile = site_instance->browsing_instance()->profile();
- ExtensionService* service = profile->GetExtensionService();
- if (!service)
- return;
-
- ExtensionProcessManager* process_manager =
- profile->GetExtensionProcessManager();
- CHECK(process_manager);
-
- // This can happen if somebody typos a chrome-extension:// URL.
- const Extension* extension = service->GetExtensionByURL(site);
- if (!extension)
- return;
-
- site_instance->GetProcess()->mark_is_extension_process();
-
- // Register the association between extension and process with
- // ExtensionProcessManager.
- process_manager->RegisterExtensionProcess(extension->id(), process->id());
-
- // Record which, if any, installed app is associated with this process.
- // TODO(aa): Totally lame to store this state in a global map in extension
- // service. Can we get it from EPM instead?
- if (extension->is_app())
- service->SetInstalledAppForRenderer(process->id(), extension);
-
- // Some extensions use chrome:// URLs.
- Extension::Type type = extension->GetType();
- if (type == Extension::TYPE_EXTENSION ||
- type == Extension::TYPE_PACKAGED_APP) {
- ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
- process->id(), chrome::kChromeUIScheme);
- }
-
- // Enable extension bindings for the renderer. Currently only extensions,
- // packaged apps, and hosted component apps use extension bindings.
- if (type == Extension::TYPE_EXTENSION ||
- type == Extension::TYPE_PACKAGED_APP ||
- (type == Extension::TYPE_HOSTED_APP &&
- extension->location() == Extension::COMPONENT)) {
- render_view_host->Send(new ExtensionMsg_ActivateExtension(extension->id()));
- render_view_host->AllowBindings(BindingsPolicy::EXTENSION);
- }
-}
-
-}
-
namespace chrome {
void ChromeContentBrowserClient::RenderViewHostCreated(
@@ -115,8 +50,24 @@ void ChromeContentBrowserClient::RenderViewHostCreated(
new DesktopNotificationHandler(render_view_host);
new DevToolsHandler(render_view_host);
new ExtensionMessageHandler(render_view_host);
+}
- InitRenderViewHostForExtensions(render_view_host);
+void ChromeContentBrowserClient::PreCreateRenderView(
+ RenderViewHost* render_view_host,
+ Profile* profile,
+ const GURL& url) {
+ // Tell the RenderViewHost whether it will be used for an extension process.
+ ExtensionService* service = profile->GetExtensionService();
+ if (service) {
+ bool is_extension_process = service->ExtensionBindingsAllowed(url);
+ render_view_host->set_is_extension_process(is_extension_process);
+
+ const Extension* installed_app = service->GetInstalledApp(url);
+ if (installed_app) {
+ service->SetInstalledAppForRenderer(
+ render_view_host->process()->id(), installed_app);
+ }
+ }
}
void ChromeContentBrowserClient::BrowserRenderProcessHostCreated(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 2ba3e24..ee81fd3 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -13,6 +13,9 @@ namespace chrome {
class ChromeContentBrowserClient : public content::ContentBrowserClient {
public:
virtual void RenderViewHostCreated(RenderViewHost* render_view_host);
+ virtual void PreCreateRenderView(RenderViewHost* render_view_host,
+ Profile* profile,
+ const GURL& url);
virtual void BrowserRenderProcessHostCreated(BrowserRenderProcessHost* host);
virtual void WorkerProcessHostCreated(WorkerProcessHost* host);
virtual content::WebUIFactory* GetWebUIFactory();
diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc
index 6d89d373..6f23fe8 100644
--- a/chrome/browser/extensions/extension_bookmark_manager_api.cc
+++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc
@@ -365,13 +365,12 @@ bool StartDragBookmarkManagerFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(
GetNodesFromArguments(model, args_.get(), 0, &nodes));
- if (render_view_host_->delegate()->GetRenderViewType() ==
+ if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() ==
ViewType::TAB_CONTENTS) {
- TabContents* tab_contents =
- dispatcher()->delegate()->GetAssociatedTabContents();
- CHECK(tab_contents);
- bookmark_utils::DragBookmarks(profile(), nodes,
- tab_contents->GetNativeView());
+ ExtensionWebUI* web_ui =
+ static_cast<ExtensionWebUI*>(dispatcher()->delegate());
+ bookmark_utils::DragBookmarks(
+ profile(), nodes, web_ui->tab_contents()->GetNativeView());
return true;
} else {
@@ -407,14 +406,10 @@ bool DropBookmarkManagerFunction::RunImpl() {
else
drop_index = drop_parent->child_count();
- if (render_view_host_->delegate()->GetRenderViewType() ==
+ if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() ==
ViewType::TAB_CONTENTS) {
- TabContents* tab_contents =
- dispatcher()->delegate()->GetAssociatedTabContents();
- CHECK(tab_contents);
ExtensionWebUI* web_ui =
- static_cast<ExtensionWebUI*>(tab_contents->web_ui());
- CHECK(web_ui);
+ static_cast<ExtensionWebUI*>(dispatcher()->delegate());
ExtensionBookmarkManagerEventRouter* router =
web_ui->extension_bookmark_manager_event_router();
diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc
index 37a814f..1777e79 100644
--- a/chrome/browser/extensions/extension_bookmarks_module.cc
+++ b/chrome/browser/extensions/extension_bookmarks_module.cc
@@ -856,7 +856,7 @@ void BookmarksIOFunction::ShowSelectFileDialog(SelectFileDialog::Type type,
file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html"));
TabContents* tab_contents = dispatcher()->delegate()->
- GetAssociatedTabContents();
+ associated_tab_contents();
// |tab_contents| can be NULL (for background pages), which is fine. In such
// a case if file-selection dialogs are forbidden by policy, we will not
diff --git a/chrome/browser/extensions/extension_file_browser_private_api.cc b/chrome/browser/extensions/extension_file_browser_private_api.cc
index 6063d3c..bff14a5 100644
--- a/chrome/browser/extensions/extension_file_browser_private_api.cc
+++ b/chrome/browser/extensions/extension_file_browser_private_api.cc
@@ -352,7 +352,8 @@ void RequestLocalFileSystemFunction::RequestOnFileThread(
}
bool RequestLocalFileSystemFunction::RunImpl() {
- if (!dispatcher() || !render_view_host() || !render_view_host()->process())
+ if (!dispatcher() || !dispatcher()->render_view_host() ||
+ !dispatcher()->render_view_host()->process())
return false;
BrowserThread::PostTask(
@@ -360,7 +361,7 @@ bool RequestLocalFileSystemFunction::RunImpl() {
NewRunnableMethod(this,
&RequestLocalFileSystemFunction::RequestOnFileThread,
source_url_,
- render_view_host()->process()->id()));
+ dispatcher()->render_view_host()->process()->id()));
// Will finish asynchronously.
return true;
}
@@ -677,7 +678,7 @@ void ExecuteTasksFileBrowserFunction::RequestFileEntryOnFileThread(
new ExecuteTasksFileSystemCallbackDispatcher(
this,
profile(),
- render_view_host()->process()->id(),
+ dispatcher()->render_view_host()->process()->id(),
source_url,
GetExtension(),
task_id,
@@ -803,13 +804,13 @@ FileDialogFunction::Callback::Find(int32 tab_id) {
int32 FileDialogFunction::GetTabId() const {
- return dispatcher()->delegate()->GetAssociatedTabContents()->
+ return dispatcher()->delegate()->associated_tab_contents()->
controller().session_id().id();
}
const FileDialogFunction::Callback& FileDialogFunction::GetCallback() const {
if (!dispatcher() || !dispatcher()->delegate() ||
- !dispatcher()->delegate()->GetAssociatedTabContents()) {
+ !dispatcher()->delegate()->associated_tab_contents()) {
return Callback::null();
}
return Callback::Find(GetTabId());
@@ -817,7 +818,7 @@ const FileDialogFunction::Callback& FileDialogFunction::GetCallback() const {
void FileDialogFunction::CloseDialog(HtmlDialogView* dialog) {
DCHECK(dialog);
- TabContents* contents = dispatcher()->delegate()->GetAssociatedTabContents();
+ TabContents* contents = dispatcher()->delegate()->associated_tab_contents();
if (contents)
dialog->CloseContents(contents);
}
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index f390d72..9f0d065 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -9,31 +9,6 @@
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/extensions/extension_messages.h"
-#include "content/browser/renderer_host/render_process_host.h"
-#include "content/browser/renderer_host/render_view_host.h"
-#include "content/browser/user_metrics.h"
-#include "content/common/notification_source.h"
-#include "content/common/notification_type.h"
-#include "content/common/result_codes.h"
-
-ExtensionFunction::RenderViewHostTracker::RenderViewHostTracker(
- ExtensionFunction* function)
- : function_(function) {
- registrar_.Add(this,
- NotificationType::RENDER_VIEW_HOST_DELETED,
- Source<RenderViewHost>(function->render_view_host()));
-}
-
-void ExtensionFunction::RenderViewHostTracker::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- CHECK(type == NotificationType::RENDER_VIEW_HOST_DELETED);
- CHECK(Source<RenderViewHost>(source).ptr() ==
- function_->render_view_host());
- function_->SetRenderViewHost(NULL);
-}
ExtensionFunction::ExtensionFunction()
: request_id_(-1),
@@ -46,11 +21,6 @@ ExtensionFunction::ExtensionFunction()
ExtensionFunction::~ExtensionFunction() {
}
-void ExtensionFunction::SetRenderViewHost(RenderViewHost* render_view_host) {
- render_view_host_ = render_view_host;
- tracker_.reset(render_view_host ? new RenderViewHostTracker(this) : NULL);
-}
-
const Extension* ExtensionFunction::GetExtension() {
ExtensionService* service = profile_->GetExtensionService();
DCHECK(service);
@@ -58,7 +28,7 @@ const Extension* ExtensionFunction::GetExtension() {
}
Browser* ExtensionFunction::GetCurrentBrowser() {
- return dispatcher()->GetCurrentBrowser(render_view_host_, include_incognito_);
+ return dispatcher()->GetCurrentBrowser(include_incognito_);
}
AsyncExtensionFunction::AsyncExtensionFunction()
@@ -91,28 +61,12 @@ void AsyncExtensionFunction::Run() {
}
void AsyncExtensionFunction::SendResponse(bool success) {
- if (!render_view_host_ || !dispatcher())
+ if (!dispatcher())
return;
if (bad_message_) {
- HandleBadMessage();
- return;
- }
-
- render_view_host_->Send(new ExtensionMsg_Response(
- render_view_host_->routing_id(), request_id_, success,
- GetResult(), GetError()));
-}
-
-void AsyncExtensionFunction::HandleBadMessage() {
- LOG(ERROR) << "bad extension message " << name_ << " : terminating renderer.";
- if (RenderProcessHost::run_renderer_in_process()) {
- // In single process mode it is better if we don't suicide but just crash.
- CHECK(false);
+ dispatcher()->HandleBadMessage(this);
} else {
- NOTREACHED();
- UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD"));
- base::KillProcess(render_view_host_->process()->GetHandle(),
- ResultCodes::KILLED_BAD_MESSAGE, false);
+ dispatcher()->SendResponse(this, success);
}
}
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index 7806a0a..7913703 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -11,8 +11,6 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "content/common/notification_observer.h"
-#include "content/common/notification_registrar.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
class ExtensionFunctionDispatcher;
@@ -39,13 +37,10 @@ class Value;
// Abstract base class for extension functions the ExtensionFunctionDispatcher
// knows how to dispatch to.
-class ExtensionFunction
- : public base::RefCountedThreadSafe<ExtensionFunction> {
+class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> {
public:
ExtensionFunction();
- virtual ~ExtensionFunction();
-
// Specifies the name of the function.
void set_name(const std::string& name) { name_ = name; }
const std::string name() const { return name_; }
@@ -61,9 +56,6 @@ class ExtensionFunction
}
std::string extension_id() const { return extension_id_; }
- void SetRenderViewHost(RenderViewHost* render_view_host);
- RenderViewHost* render_view_host() const { return render_view_host_; }
-
// Specifies the raw arguments to the function, as a JSON value.
virtual void SetArgs(const ListValue* args) = 0;
@@ -110,6 +102,8 @@ class ExtensionFunction
protected:
friend class base::RefCountedThreadSafe<ExtensionFunction>;
+ virtual ~ExtensionFunction();
+
// Gets the extension that called this function. This can return NULL for
// async functions, for example if the extension is unloaded while the
// function is running.
@@ -136,9 +130,6 @@ class ExtensionFunction
// The peer to the dispatcher that will service this extension function call.
scoped_refptr<ExtensionFunctionDispatcher::Peer> peer_;
- // The RenderViewHost we will send responses too.
- RenderViewHost* render_view_host_;
-
// Id of this request, used to map the response back to the caller.
int request_id_;
@@ -167,26 +158,6 @@ class ExtensionFunction
// True if the call was made in response of user gesture.
bool user_gesture_;
- private:
- // Helper class to track the lifetime of ExtensionFunction's RenderViewHost
- // pointer and NULL it out when it dies. We use this separate class (instead
- // of implementing NotificationObserver on ExtensionFunction) because it is
- // common for subclasses of ExtensionFunction to be NotificationObservers, and
- // it would be an easy error to forget to call the base class's Observe()
- // method.
- class RenderViewHostTracker : public NotificationObserver {
- public:
- explicit RenderViewHostTracker(ExtensionFunction* extension_function);
- private:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
- ExtensionFunction* function_;
- NotificationRegistrar registrar_;
- };
-
- scoped_ptr<RenderViewHostTracker> tracker_;
-
DISALLOW_COPY_AND_ASSIGN(ExtensionFunction);
};
@@ -233,13 +204,6 @@ class AsyncExtensionFunction : public ExtensionFunction {
// returning. The calling renderer process will be killed.
bool bad_message_;
- private:
- // Called when we receive an extension api request that is invalid in a way
- // that JSON validation in the renderer should have caught. This should never
- // happen and could be an attacker trying to exploit the browser, so we crash
- // the renderer instead.
- void HandleBadMessage();
-
DISALLOW_COPY_AND_ASSIGN(AsyncExtensionFunction);
};
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 8a27836..6a69d42 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -30,6 +30,7 @@
#include "chrome/browser/extensions/extension_omnibox_api.h"
#include "chrome/browser/extensions/extension_page_actions_module.h"
#include "chrome/browser/extensions/extension_preference_api.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_processes_api.h"
#include "chrome/browser/extensions/extension_proxy_api.h"
#include "chrome/browser/extensions/extension_rlz_module.h"
@@ -51,6 +52,9 @@
#include "content/browser/child_process_security_policy.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/user_metrics.h"
+#include "content/common/notification_service.h"
+#include "content/common/result_codes.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -381,19 +385,71 @@ void ExtensionFunctionDispatcher::ResetFunctions() {
FactoryRegistry::GetInstance()->ResetFunctions();
}
-ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile,
- Delegate* delegate)
- : profile_(profile),
+ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create(
+ RenderViewHost* render_view_host,
+ Delegate* delegate,
+ const GURL& url) {
+ ExtensionService* service =
+ render_view_host->process()->profile()->GetExtensionService();
+ DCHECK(service);
+
+ if (!service->ExtensionBindingsAllowed(url))
+ return NULL;
+
+ const Extension* extension = service->GetExtensionByURL(url);
+ if (!extension)
+ extension = service->GetExtensionByWebExtent(url);
+
+ if (extension)
+ return new ExtensionFunctionDispatcher(render_view_host, delegate,
+ extension, url);
+ else
+ return NULL;
+}
+
+ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
+ RenderViewHost* render_view_host,
+ Delegate* delegate,
+ const Extension* extension,
+ const GURL& url)
+ : profile_(render_view_host->process()->profile()),
+ render_view_host_(render_view_host),
delegate_(delegate),
+ url_(url),
+ extension_id_(extension->id()),
ALLOW_THIS_IN_INITIALIZER_LIST(peer_(new Peer(this))) {
+ // TODO(erikkay) should we do something for these errors in Release?
+ DCHECK(extension);
+ DCHECK(url.SchemeIs(chrome::kExtensionScheme) ||
+ extension->location() == Extension::COMPONENT);
+
+ // Notify the ExtensionProcessManager that the view was created.
+ ExtensionProcessManager* epm = profile()->GetExtensionProcessManager();
+ epm->RegisterExtensionProcess(extension_id(),
+ render_view_host->process()->id());
+
+ // Activate this extension in the renderer. This must be done before any
+ // extension JavaScript code runs because it controls some privileges the
+ // extension code has in the renderer.
+ render_view_host->Send(new ExtensionMsg_ActivateExtension(extension->id()));
+
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED,
+ Source<Profile>(profile_),
+ Details<ExtensionFunctionDispatcher>(this));
}
ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
peer_->dispatcher_ = NULL;
+
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED,
+ Source<Profile>(profile_),
+ Details<ExtensionFunctionDispatcher>(this));
}
Browser* ExtensionFunctionDispatcher::GetCurrentBrowser(
- RenderViewHost* render_view_host, bool include_incognito) {
+ bool include_incognito) {
Browser* browser = delegate_->GetBrowser();
// If the delegate has an associated browser, that is always the right answer.
@@ -405,7 +461,7 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser(
// profile. Note that the profile may already be incognito, in which case
// we will search the incognito version only, regardless of the value of
// |include_incognito|.
- Profile* profile = render_view_host->process()->profile();
+ Profile* profile = render_view_host()->process()->profile();
browser = BrowserList::FindTabbedBrowser(profile, include_incognito);
// NOTE(rafaelw): This can return NULL in some circumstances. In particular,
@@ -417,84 +473,88 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser(
return browser;
}
-void ExtensionFunctionDispatcher::Dispatch(
- const ExtensionHostMsg_Request_Params& params,
- RenderViewHost* render_view_host) {
- // TODO(aa): It would be cool to use ExtensionProcessManager to track which
- // processes are extension processes rather than ChildProcessSecurityPolicy.
- // EPM has richer information: it not only knows which processes contain
- // at least one extension, but it knows which extensions are inside and what
- // permissions the have. So we would be able to enforce permissions more
- // granularly.
- if (!ChildProcessSecurityPolicy::GetInstance()->HasExtensionBindings(
- render_view_host->process()->id())) {
- // TODO(aa): Allow content scripts access to low-threat extension APIs.
- // See: crbug.com/80308.
- LOG(ERROR) << "Extension API called from non-extension process.";
- SendAccessDenied(render_view_host, params.request_id);
- return;
- }
-
- ExtensionService* service = profile()->GetExtensionService();
- if (!service)
- return;
-
- if (!service->ExtensionBindingsAllowed(params.source_url)) {
- LOG(ERROR) << "Extension bindings not allowed for URL: "
- << params.source_url.spec();
- SendAccessDenied(render_view_host, params.request_id);
- return;
- }
-
- // TODO(aa): When we allow content scripts to call extension APIs, we will
- // have to pass the extension ID explicitly here, not use the source URL.
- const Extension* extension = service->GetExtensionByURL(params.source_url);
- if (!extension)
- extension = service->GetExtensionByWebExtent(params.source_url);
- if (!extension) {
- LOG(ERROR) << "Extension does not exist for URL: "
- << params.source_url.spec();
- SendAccessDenied(render_view_host, params.request_id);
- return;
- }
+bool ExtensionFunctionDispatcher::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ExtensionFunctionDispatcher, message)
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
- if (!extension->HasApiPermission(params.name)) {
- LOG(ERROR) << "Extension " << extension->id() << " does not have "
- << "permission to function: " << params.name;
- SendAccessDenied(render_view_host, params.request_id);
+void ExtensionFunctionDispatcher::OnRequest(
+ const ExtensionHostMsg_Request_Params& params) {
+ if (!ChildProcessSecurityPolicy::GetInstance()->
+ HasExtensionBindings(render_view_host_->process()->id())) {
+ // This can happen if someone uses window.open() to open an extension URL
+ // from a non-extension context.
+ render_view_host_->Send(new ExtensionMsg_Response(
+ render_view_host_->routing_id(), params.request_id, false,
+ std::string(), "Access to extension API denied."));
return;
}
scoped_refptr<ExtensionFunction> function(
FactoryRegistry::GetInstance()->NewFunction(params.name));
- function->SetRenderViewHost(render_view_host);
function->set_dispatcher_peer(peer_);
function->set_profile(profile_);
- function->set_extension_id(extension->id());
+ function->set_extension_id(extension_id());
function->SetArgs(&params.arguments);
function->set_source_url(params.source_url);
function->set_request_id(params.request_id);
function->set_has_callback(params.has_callback);
function->set_user_gesture(params.user_gesture);
+ ExtensionService* service = profile()->GetExtensionService();
+ DCHECK(service);
+ const Extension* extension = service->GetExtensionById(extension_id(), false);
+ DCHECK(extension);
function->set_include_incognito(service->CanCrossIncognito(extension));
+ if (!service->ExtensionBindingsAllowed(function->source_url()) ||
+ !extension->HasApiPermission(function->name())) {
+ render_view_host_->Send(new ExtensionMsg_Response(
+ render_view_host_->routing_id(), function->request_id(), false,
+ std::string(), "Access to extension API denied."));
+ return;
+ }
+
ExtensionsQuotaService* quota = service->quota_service();
- if (quota->Assess(extension->id(), function, &params.arguments,
+ if (quota->Assess(extension_id(), function, &params.arguments,
base::TimeTicks::Now())) {
// See crbug.com/39178.
ExternalProtocolHandler::PermitLaunchUrl();
function->Run();
} else {
- render_view_host->Send(new ExtensionMsg_Response(
- render_view_host->routing_id(), function->request_id(), false,
+ render_view_host_->Send(new ExtensionMsg_Response(
+ render_view_host_->routing_id(), function->request_id(), false,
std::string(), QuotaLimitHeuristic::kGenericOverQuotaError));
}
}
-void ExtensionFunctionDispatcher::SendAccessDenied(
- RenderViewHost* render_view_host, int request_id) {
- render_view_host->Send(new ExtensionMsg_Response(
- render_view_host->routing_id(), request_id, false, std::string(),
- "Access to extension API denied."));
+void ExtensionFunctionDispatcher::SendResponse(ExtensionFunction* function,
+ bool success) {
+ render_view_host_->Send(new ExtensionMsg_Response(
+ render_view_host_->routing_id(), function->request_id(), success,
+ function->GetResult(), function->GetError()));
+}
+
+void ExtensionFunctionDispatcher::HandleBadMessage(ExtensionFunction* api) {
+ LOG(ERROR) << "bad extension message " <<
+ api->name() <<
+ " : terminating renderer.";
+ if (RenderProcessHost::run_renderer_in_process()) {
+ // In single process mode it is better if we don't suicide but just crash.
+ CHECK(false);
+ } else {
+ NOTREACHED();
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD"));
+ base::KillProcess(render_view_host_->process()->GetHandle(),
+ ResultCodes::KILLED_BAD_MESSAGE, false);
+ }
+}
+
+Profile* ExtensionFunctionDispatcher::profile() {
+ return profile_;
}
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index d3b8d1c..9f91d9d 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -11,6 +11,7 @@
#include "base/memory/ref_counted.h"
#include "googleurl/src/gurl.h"
+#include "ipc/ipc_channel.h"
#include "ui/gfx/native_widget_types.h"
class Browser;
@@ -26,19 +27,9 @@ struct ExtensionHostMsg_Request_Params;
typedef ExtensionFunction* (*ExtensionFunctionFactory)();
// ExtensionFunctionDispatcher receives requests to execute functions from
-// Chrome extensions running in a RenderViewHost and dispatches them to the
+// Chromium extensions running in a RenderViewHost and dispatches them to the
// appropriate handler. It lives entirely on the UI thread.
-//
-// ExtensionFunctionDispatcher should be a member of some class that hosts
-// RenderViewHosts and wants them to be able to display extension content.
-// This class should also implement ExtensionFunctionDispatcher::Delegate.
-//
-// Note that a single ExtensionFunctionDispatcher does *not* correspond to a
-// single RVH, a single extension, or a single URL. This is by design so that
-// we can gracefully handle cases like TabContents, where the RVH, extension,
-// and URL can all change over the lifetime of the tab. Instead, these items
-// are all passed into each request.
-class ExtensionFunctionDispatcher {
+class ExtensionFunctionDispatcher : public IPC::Channel::Listener {
public:
class Delegate {
public:
@@ -54,7 +45,7 @@ class ExtensionFunctionDispatcher {
// context. For example, the TabContents in which an infobar or
// chrome-extension://<id> URL are being shown. Callers must check for a
// NULL return value (as in the case of a background page).
- virtual TabContents* GetAssociatedTabContents() const = 0;
+ virtual TabContents* associated_tab_contents() const = 0;
protected:
virtual ~Delegate() {}
@@ -85,19 +76,21 @@ class ExtensionFunctionDispatcher {
// Resets all functions to their initial implementation.
static void ResetFunctions();
- // Public constructor. Callers must ensure that:
- // - |delegate| outlives this object.
- // - This object outlives any RenderViewHost's passed to created
- // ExtensionFunctions.
- ExtensionFunctionDispatcher(Profile* profile, Delegate* delegate);
+ // Creates an instance for the specified RenderViewHost and URL. If the URL
+ // does not contain a valid extension, returns NULL.
+ static ExtensionFunctionDispatcher* Create(RenderViewHost* render_view_host,
+ Delegate* delegate,
+ const GURL& url);
~ExtensionFunctionDispatcher();
Delegate* delegate() { return delegate_; }
- // Message handlers.
- void Dispatch(const ExtensionHostMsg_Request_Params& params,
- RenderViewHost* sender);
+ // If |message| is an extension request, handle it. Returns true if handled.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ // Send a response to a function.
+ void SendResponse(ExtensionFunction* api, bool success);
// Returns the current browser. Callers should generally prefer
// ExtensionFunction::GetCurrentBrowser() over this method, as that one
@@ -105,20 +98,46 @@ class ExtensionFunctionDispatcher {
//
// See the comments for ExtensionFunction::GetCurrentBrowser() for more
// details.
- Browser* GetCurrentBrowser(RenderViewHost* render_view_host,
- bool include_incognito);
+ Browser* GetCurrentBrowser(bool include_incognito);
+
+ // Handle a malformed message. Possibly the result of an attack, so kill
+ // the renderer.
+ void HandleBadMessage(ExtensionFunction* api);
+
+ // Gets the URL for the view we're displaying.
+ const GURL& url() { return url_; }
+
+ // Gets the ID for this extension.
+ const std::string extension_id() { return extension_id_; }
// The profile that this dispatcher is associated with.
- Profile* profile() { return profile_; }
+ Profile* profile();
+
+ // The RenderViewHost this dispatcher is associated with.
+ RenderViewHost* render_view_host() { return render_view_host_; }
private:
- // Helper to send an access denied error to the requesting render view.
- void SendAccessDenied(RenderViewHost* render_view_host, int request_id);
+ ExtensionFunctionDispatcher(RenderViewHost* render_view_host,
+ Delegate* delegate,
+ const Extension* extension,
+ const GURL& url);
+ // Message handlers.
+ void OnRequest(const ExtensionHostMsg_Request_Params& params);
+
+ // We need to keep a pointer to the profile because we use it in the dtor
+ // in sending EXTENSION_FUNCTION_DISPATCHER_DESTROYED, but by that point
+ // the render_view_host_ has been deleted.
Profile* profile_;
+ RenderViewHost* render_view_host_;
+
Delegate* delegate_;
+ GURL url_;
+
+ std::string extension_id_;
+
scoped_refptr<Peer> peer_;
};
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 318ca0b..7badebf 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -28,7 +28,6 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/view_types.h"
@@ -132,13 +131,17 @@ ExtensionHost::ExtensionHost(const Extension* extension,
did_stop_loading_(false),
document_element_available_(false),
url_(url),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- extension_function_dispatcher_(profile_, this)),
extension_host_type_(host_type),
associated_tab_contents_(NULL),
suppress_javascript_messages_(false) {
render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE,
NULL);
+ render_view_host_->set_is_extension_process(true);
+ if (extension->is_app()) {
+ profile()->GetExtensionService()->SetInstalledAppForRenderer(
+ render_view_host_->process()->id(), extension);
+ }
+ render_view_host_->AllowBindings(BindingsPolicy::EXTENSION);
if (enable_dom_automation_)
render_view_host_->AllowBindings(BindingsPolicy::DOM_AUTOMATION);
@@ -179,7 +182,7 @@ void ExtensionHost::CreateView(Browser* browser) {
#endif
}
-TabContents* ExtensionHost::GetAssociatedTabContents() const {
+TabContents* ExtensionHost::associated_tab_contents() const {
return associated_tab_contents_;
}
@@ -311,9 +314,6 @@ void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host,
if (!extension_)
return;
- // TODO(aa): This is suspicious. There can be multiple views in an extension,
- // and they aren't all going to use ExtensionHost. This should be in someplace
- // more central, like EPM maybe.
DCHECK_EQ(render_view_host_, render_view_host);
NotificationService::current()->Notify(
NotificationType::EXTENSION_PROCESS_TERMINATED,
@@ -327,7 +327,29 @@ void ExtensionHost::DidNavigate(RenderViewHost* render_view_host,
if (!PageTransition::IsMainFrame(params.transition))
return;
+ if (!params.url.SchemeIs(chrome::kExtensionScheme)) {
+ extension_function_dispatcher_.reset(NULL);
+ url_ = params.url;
+ return;
+ }
+
+ // This catches two bogus use cases:
+ // (1) URLs that look like chrome-extension://somethingbogus or
+ // chrome-extension://nosuchid/, in other words, no Extension would
+ // be found.
+ // (2) URLs that refer to a different extension than this one.
+ // In both cases, we preserve the old URL and reset the EFD to NULL. This
+ // will leave the host in kind of a bad state with poor UI and errors, but
+ // it's better than the alternative.
+ // TODO(erikkay) Perhaps we should display errors in developer mode.
+ if (params.url.host() != extension_id()) {
+ extension_function_dispatcher_.reset(NULL);
+ return;
+ }
+
url_ = params.url;
+ extension_function_dispatcher_.reset(
+ ExtensionFunctionDispatcher::Create(render_view_host_, this, url_));
}
void ExtensionHost::InsertInfobarCSS() {
@@ -443,8 +465,7 @@ gfx::NativeWindow ExtensionHost::GetMessageBoxRootWindow() {
return platform_util::GetTopLevel(native_view);
// Otherwise, try the active tab's view.
- Browser* browser = extension_function_dispatcher_.GetCurrentBrowser(
- render_view_host_, true);
+ Browser* browser = extension_function_dispatcher_->GetCurrentBrowser(true);
if (browser) {
TabContents* active_tab = browser->GetSelectedTabContents();
if (active_tab)
@@ -486,7 +507,7 @@ void ExtensionHost::Close(RenderViewHost* render_view_host) {
RendererPreferences ExtensionHost::GetRendererPrefs(Profile* profile) const {
RendererPreferences preferences;
- TabContents* associated_contents = GetAssociatedTabContents();
+ TabContents* associated_contents = associated_tab_contents();
if (associated_contents)
preferences =
static_cast<RenderViewHostDelegate*>(associated_contents)->
@@ -540,7 +561,7 @@ void ExtensionHost::CreateNewWindow(
params.window_container_type,
params.frame_name);
- TabContents* associated_contents = GetAssociatedTabContents();
+ TabContents* associated_contents = associated_tab_contents();
if (associated_contents && associated_contents->delegate())
associated_contents->delegate()->TabContentsCreated(new_contents);
}
@@ -595,7 +616,7 @@ void ExtensionHost::ShowCreatedWindow(int route_id,
// the case of extensions in 'spanning' incognito mode, they can mismatch.
// We don't want to end up putting a normal tab into an incognito window, or
// vice versa.
- TabContents* associated_contents = GetAssociatedTabContents();
+ TabContents* associated_contents = associated_tab_contents();
if (associated_contents &&
associated_contents->profile() == contents->profile()) {
associated_contents->AddNewContents(
@@ -753,19 +774,19 @@ ViewType::Type ExtensionHost::GetRenderViewType() const {
}
bool ExtensionHost::OnMessageReceived(const IPC::Message& message) {
+ if (extension_function_dispatcher_.get() &&
+ extension_function_dispatcher_->OnMessageReceived(message)) {
+ return true;
+ }
+
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message)
IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser)
- IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void ExtensionHost::OnRequest(const ExtensionHostMsg_Request_Params& params) {
- extension_function_dispatcher_.Dispatch(params, render_view_host_);
-}
-
const GURL& ExtensionHost::GetURL() const {
return url_;
}
@@ -774,6 +795,13 @@ void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) {
if (view_.get())
view_->RenderViewCreated();
+ // TODO(mpcomplete): This is duplicated in DidNavigate, which means that
+ // we'll create 2 EFDs for the first navigation. We should try to find a
+ // better way to unify them.
+ // See http://code.google.com/p/chromium/issues/detail?id=18240
+ extension_function_dispatcher_.reset(
+ ExtensionFunctionDispatcher::Create(render_view_host, this, url_));
+
if (extension_host_type_ == ViewType::EXTENSION_POPUP ||
extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
render_view_host->EnablePreferredSizeChangedMode(
@@ -804,5 +832,5 @@ void ExtensionHost::OnRunFileChooser(
if (file_select_helper_.get() == NULL)
file_select_helper_.reset(new FileSelectHelper(profile()));
file_select_helper_->RunFileChooser(render_view_host_,
- GetAssociatedTabContents(), params);
+ associated_tab_contents(), params);
}
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index 87b691c..311975d 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -86,7 +86,7 @@ class ExtensionHost : public RenderViewHostDelegate,
ViewType::Type extension_host_type() const { return extension_host_type_; }
// ExtensionFunctionDispatcher::Delegate
- virtual TabContents* GetAssociatedTabContents() const;
+ virtual TabContents* associated_tab_contents() const;
void set_associated_tab_contents(TabContents* associated_tab_contents) {
associated_tab_contents_ = associated_tab_contents;
}
@@ -229,7 +229,6 @@ class ExtensionHost : public RenderViewHostDelegate,
// Message handlers.
void OnRunFileChooser(const ViewHostMsg_RunFileChooser_Params& params);
- void OnRequest(const ExtensionHostMsg_Request_Params& params);
// Handles keyboard events that were not handled by HandleKeyboardEvent().
// Platform specific implementation may override this method to handle the
@@ -275,7 +274,7 @@ class ExtensionHost : public RenderViewHostDelegate,
NotificationRegistrar registrar_;
- ExtensionFunctionDispatcher extension_function_dispatcher_;
+ scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
// Only EXTENSION_INFOBAR, EXTENSION_POPUP, and EXTENSION_BACKGROUND_PAGE
// are used here, others are not hosted by ExtensionHost.
diff --git a/chrome/browser/extensions/extension_tab_helper.cc b/chrome/browser/extensions/extension_tab_helper.cc
index 8a1caa5..6f44f6c 100644
--- a/chrome/browser/extensions/extension_tab_helper.cc
+++ b/chrome/browser/extensions/extension_tab_helper.cc
@@ -6,15 +6,12 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h"
#include "chrome/common/extensions/extension_action.h"
#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/extension_resource.h"
-#include "content/browser/renderer_host/render_widget_host_view.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/common/notification_service.h"
@@ -22,8 +19,6 @@
ExtensionTabHelper::ExtensionTabHelper(TabContentsWrapper* wrapper)
: TabContentsObserver(wrapper->tab_contents()),
extension_app_(NULL),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- extension_function_dispatcher_(wrapper->profile(), this)),
wrapper_(wrapper) {
}
@@ -118,7 +113,6 @@ bool ExtensionTabHelper::OnMessageReceived(const IPC::Message& message) {
OnDidGetApplicationInfo)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_InstallApplication,
OnInstallApplication)
- IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -137,12 +131,6 @@ void ExtensionTabHelper::OnInstallApplication(const WebApplicationInfo& info) {
wrapper_->delegate()->OnInstallApplication(wrapper_, info);
}
-void ExtensionTabHelper::OnRequest(
- const ExtensionHostMsg_Request_Params& request) {
- extension_function_dispatcher_.Dispatch(request,
- tab_contents()->render_view_host());
-}
-
void ExtensionTabHelper::UpdateExtensionAppIcon(const Extension* extension) {
extension_app_icon_.reset();
@@ -173,37 +161,3 @@ void ExtensionTabHelper::OnImageLoaded(SkBitmap* image,
tab_contents()->NotifyNavigationStateChanged(TabContents::INVALIDATE_TAB);
}
}
-
-Browser* ExtensionTabHelper::GetBrowser() {
- TabContents* contents = tab_contents();
- TabContentsIterator tab_iterator;
- for (; !tab_iterator.done(); ++tab_iterator) {
- if (contents == (*tab_iterator)->tab_contents())
- return tab_iterator.browser();
- }
-
- return NULL;
-}
-
-TabContents* ExtensionTabHelper::GetAssociatedTabContents() const {
- return tab_contents();
-}
-
-gfx::NativeWindow ExtensionTabHelper::GetCustomFrameNativeWindow() {
- if (GetBrowser())
- return NULL;
-
- // If there was no browser associated with the function dispatcher delegate,
- // then this WebUI may be hosted in an ExternalTabContainer, and a framing
- // window will be accessible through the tab_contents.
- TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate();
- if (tab_contents_delegate)
- return tab_contents_delegate->GetFrameNativeWindow();
- else
- return NULL;
-}
-
-gfx::NativeView ExtensionTabHelper::GetNativeViewOfHost() {
- RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
- return rwhv ? rwhv->GetNativeView() : NULL;
-}
diff --git a/chrome/browser/extensions/extension_tab_helper.h b/chrome/browser/extensions/extension_tab_helper.h
index 8a4b51e..46b0348 100644
--- a/chrome/browser/extensions/extension_tab_helper.h
+++ b/chrome/browser/extensions/extension_tab_helper.h
@@ -7,7 +7,6 @@
#pragma once
#include "content/browser/tab_contents/tab_contents_observer.h"
-#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/common/web_apps.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -18,7 +17,6 @@ struct WebApplicationInfo;
// Per-tab extension helper. Also handles non-extension apps.
class ExtensionTabHelper : public TabContentsObserver,
- public ExtensionFunctionDispatcher::Delegate,
public ImageLoadingTracker::Observer {
public:
explicit ExtensionTabHelper(TabContentsWrapper* wrapper);
@@ -79,16 +77,9 @@ class ExtensionTabHelper : public TabContentsObserver,
const ViewHostMsg_FrameNavigate_Params& params) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message);
- // ExtensionFunctionDispatcher::Delegate overrides.
- virtual Browser* GetBrowser();
- virtual gfx::NativeView GetNativeViewOfHost();
- virtual gfx::NativeWindow GetCustomFrameNativeWindow();
- virtual TabContents* GetAssociatedTabContents() const;
-
// Message handlers.
void OnDidGetApplicationInfo(int32 page_id, const WebApplicationInfo& info);
void OnInstallApplication(const WebApplicationInfo& info);
- void OnRequest(const ExtensionHostMsg_Request_Params& params);
// App extensions related methods:
@@ -110,9 +101,6 @@ class ExtensionTabHelper : public TabContentsObserver,
// non-extension apps.
SkBitmap extension_app_icon_;
- // Process any extension messages coming from the tab.
- ExtensionFunctionDispatcher extension_function_dispatcher_;
-
// Used for loading extension_app_icon_.
scoped_ptr<ImageLoadingTracker> extension_app_image_loader_;
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index 97654bf..a43d894 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -793,7 +793,7 @@ bool GetTabFunction::RunImpl() {
bool GetCurrentTabFunction::RunImpl() {
DCHECK(dispatcher());
- TabContents* contents = dispatcher()->delegate()->GetAssociatedTabContents();
+ TabContents* contents = dispatcher()->delegate()->associated_tab_contents();
if (contents)
result_.reset(ExtensionTabUtil::CreateTabValue(contents));
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index a816c76..e398c46 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -24,9 +24,11 @@
#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/url_constants.h"
+#include "content/browser/renderer_host/render_widget_host_view.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/bindings_policy.h"
#include "content/common/page_transition_types.h"
+#include "ipc/ipc_message.h"
#include "net/base/file_stream.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
@@ -138,6 +140,7 @@ ExtensionWebUI::ExtensionWebUI(TabContents* tab_contents, const GURL& url)
// component apps like bookmark manager.
should_hide_url_ = !extension->is_hosted_app();
+ bindings_ = BindingsPolicy::EXTENSION;
// Bind externalHost to Extension WebUI loaded in Chrome Frame.
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
if (browser_command_line.HasSwitch(switches::kChromeFrame))
@@ -152,23 +155,86 @@ ExtensionWebUI::ExtensionWebUI(TabContents* tab_contents, const GURL& url)
should_hide_url_ = false;
}
}
+}
+
+ExtensionWebUI::~ExtensionWebUI() {}
+void ExtensionWebUI::ResetExtensionFunctionDispatcher(
+ RenderViewHost* render_view_host) {
+ // TODO(jcivelli): http://crbug.com/60608 we should get the URL out of the
+ // active entry of the navigation controller.
+ extension_function_dispatcher_.reset(
+ ExtensionFunctionDispatcher::Create(render_view_host, this, url_));
+ DCHECK(extension_function_dispatcher_.get());
+}
+
+void ExtensionWebUI::ResetExtensionBookmarkManagerEventRouter() {
// Hack: A few things we specialize just for the bookmark manager.
- if (extension->id() == extension_misc::kBookmarkManagerId) {
+ if (extension_function_dispatcher_->extension_id() ==
+ extension_misc::kBookmarkManagerId) {
extension_bookmark_manager_event_router_.reset(
- new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents));
+ new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents()));
link_transition_type_ = PageTransition::AUTO_BOOKMARK;
}
}
-ExtensionWebUI::~ExtensionWebUI() {}
+void ExtensionWebUI::RenderViewCreated(RenderViewHost* render_view_host) {
+ ResetExtensionFunctionDispatcher(render_view_host);
+ ResetExtensionBookmarkManagerEventRouter();
+}
+
+void ExtensionWebUI::RenderViewReused(RenderViewHost* render_view_host) {
+ ResetExtensionFunctionDispatcher(render_view_host);
+ ResetExtensionBookmarkManagerEventRouter();
+}
+
+bool ExtensionWebUI::OnMessageReceived(const IPC::Message& message) {
+ if (extension_function_dispatcher_.get())
+ return extension_function_dispatcher_->OnMessageReceived(message);
+
+ return false;
+}
+
+Browser* ExtensionWebUI::GetBrowser() {
+ TabContents* contents = tab_contents();
+ TabContentsIterator tab_iterator;
+ for (; !tab_iterator.done(); ++tab_iterator) {
+ if (contents == (*tab_iterator)->tab_contents())
+ return tab_iterator.browser();
+ }
+
+ return NULL;
+}
+
+TabContents* ExtensionWebUI::associated_tab_contents() const {
+ return tab_contents();
+}
ExtensionBookmarkManagerEventRouter*
ExtensionWebUI::extension_bookmark_manager_event_router() {
return extension_bookmark_manager_event_router_.get();
}
+gfx::NativeWindow ExtensionWebUI::GetCustomFrameNativeWindow() {
+ if (GetBrowser())
+ return NULL;
+
+ // If there was no browser associated with the function dispatcher delegate,
+ // then this WebUI may be hosted in an ExternalTabContainer, and a framing
+ // window will be accessible through the tab_contents.
+ TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate();
+ if (tab_contents_delegate)
+ return tab_contents_delegate->GetFrameNativeWindow();
+ else
+ return NULL;
+}
+
+gfx::NativeView ExtensionWebUI::GetNativeViewOfHost() {
+ RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
+ return rwhv ? rwhv->GetNativeView() : NULL;
+}
+
////////////////////////////////////////////////////////////////////////////////
// chrome:// URL overrides
diff --git a/chrome/browser/extensions/extension_web_ui.h b/chrome/browser/extensions/extension_web_ui.h
index 4aad170..3a3a80b 100644
--- a/chrome/browser/extensions/extension_web_ui.h
+++ b/chrome/browser/extensions/extension_web_ui.h
@@ -10,9 +10,11 @@
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/favicon/favicon_service.h"
#include "chrome/common/extensions/extension.h"
#include "content/browser/webui/web_ui.h"
+#include "ipc/ipc_channel.h"
class GURL;
class ListValue;
@@ -20,12 +22,15 @@ class PrefService;
class Profile;
class RenderViewHost;
class TabContents;
+struct ExtensionHostMsg_Request_Params;
// This class implements WebUI for extensions and allows extensions to put UI in
// the main tab contents area. For example, each extension can specify an
// "options_page", and that page is displayed in the tab contents area and is
// hosted by this class.
-class ExtensionWebUI : public WebUI {
+class ExtensionWebUI
+ : public WebUI,
+ public ExtensionFunctionDispatcher::Delegate {
public:
static const char kExtensionURLOverrides[];
@@ -33,6 +38,21 @@ class ExtensionWebUI : public WebUI {
virtual ~ExtensionWebUI();
+ ExtensionFunctionDispatcher* extension_function_dispatcher() const {
+ return extension_function_dispatcher_.get();
+ }
+
+ // WebUI
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ virtual void RenderViewCreated(RenderViewHost* render_view_host);
+ virtual void RenderViewReused(RenderViewHost* render_view_host);
+
+ // ExtensionFunctionDispatcher::Delegate
+ virtual Browser* GetBrowser();
+ virtual gfx::NativeView GetNativeViewOfHost();
+ virtual gfx::NativeWindow GetCustomFrameNativeWindow();
+ virtual TabContents* associated_tab_contents() const;
+
virtual ExtensionBookmarkManagerEventRouter*
extension_bookmark_manager_event_router();
@@ -67,6 +87,15 @@ class ExtensionWebUI : public WebUI {
ListValue* list,
Value* override);
+ // When the RenderViewHost changes (RenderViewCreated and RenderViewReused),
+ // we need to reset the ExtensionFunctionDispatcher so it's talking to the
+ // right one, as well as being linked to the correct URL.
+ void ResetExtensionFunctionDispatcher(RenderViewHost* render_view_host);
+
+ void ResetExtensionBookmarkManagerEventRouter();
+
+ scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+
// TODO(aa): This seems out of place. Why is it not with the event routers for
// the other extension APIs?
scoped_ptr<ExtensionBookmarkManagerEventRouter>
diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc
index 7c46cff..8dbf650 100644
--- a/chrome/browser/extensions/extension_webstore_private_api.cc
+++ b/chrome/browser/extensions/extension_webstore_private_api.cc
@@ -461,7 +461,7 @@ bool CompleteInstallFunction::RunImpl() {
// install flow. The above call to SetWhitelistedInstallId will bypass the
// normal permissions install dialog.
NavigationController& controller =
- dispatcher()->delegate()->GetAssociatedTabContents()->controller();
+ dispatcher()->delegate()->associated_tab_contents()->controller();
controller.LoadURL(url, source_url(), PageTransition::LINK);
return true;
@@ -519,7 +519,7 @@ bool PromptBrowserLoginFunction::RunImpl() {
// Login can currently only be invoked tab-modal. Since this is
// coming from the webstore, we should always have a tab, but check
// just in case.
- TabContents* tab = dispatcher()->delegate()->GetAssociatedTabContents();
+ TabContents* tab = dispatcher()->delegate()->associated_tab_contents();
if (!tab)
return false;
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 37e4fd9..8022dc4 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_disabled_infobar_delegate.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extension_service.h"
@@ -299,11 +300,13 @@ void ExtensionsDOMHandler::RegisterForNotifications() {
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED,
+ NotificationService::AllSources());
registrar_.Add(this,
- NotificationType::NAV_ENTRY_COMMITTED,
+ NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED,
NotificationService::AllSources());
registrar_.Add(this,
- NotificationType::RENDER_VIEW_HOST_CREATED,
+ NotificationType::NAV_ENTRY_COMMITTED,
NotificationService::AllSources());
registrar_.Add(this,
NotificationType::RENDER_VIEW_HOST_DELETED,
@@ -628,11 +631,9 @@ void ExtensionsDOMHandler::Observe(NotificationType type,
// we don't know about the views for an extension at EXTENSION_LOADED, but
// if we only listen to EXTENSION_PROCESS_CREATED, we'll miss extensions
// that don't have a process at startup. Similarly, NAV_ENTRY_COMMITTED &
- // RENDER_VIEW_HOST_CREATED because we want to handle both
- // the case of navigating from a non-extension page to an extension page in
- // a TabContents (which will generate NAV_ENTRY_COMMITTED) as well as
- // extension content being shown in popups and balloons (which will generate
- // RENDER_VIEW_HOST_CREATED but no NAV_ENTRY_COMMITTED).
+ // EXTENSION_FUNCTION_DISPATCHER_CREATED because we want to handle both
+ // the case of live app pages (which don't have an EFD) and
+ // chrome-extension:// urls which are served in a TabContents.
//
// Doing it this way gets everything but causes the page to be rendered
// more than we need. It doesn't seem to result in any noticeable flicker.
@@ -648,7 +649,8 @@ void ExtensionsDOMHandler::Observe(NotificationType type,
case NotificationType::EXTENSION_PROCESS_CREATED:
case NotificationType::EXTENSION_UNLOADED:
case NotificationType::EXTENSION_UPDATE_DISABLED:
- case NotificationType::RENDER_VIEW_HOST_CREATED:
+ case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED:
+ case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED:
case NotificationType::NAV_ENTRY_COMMITTED:
case NotificationType::BACKGROUND_CONTENTS_NAVIGATED:
case NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED:
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc
index 074e42d..ea1c834 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -171,7 +171,7 @@ void MemoryDetails::CollectChildInfoOnUIThread() {
}
TabContents* contents = host_delegate->GetAsTabContents();
if (!contents) {
- if (host->process()->is_extension_process()) {
+ if (host->is_extension_process()) {
const Extension* extension =
extension_service->GetExtensionByURL(url);
if (extension) {
diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc
index 7219be0..3d600a0 100644
--- a/chrome/browser/notifications/balloon_host.cc
+++ b/chrome/browser/notifications/balloon_host.cc
@@ -3,13 +3,14 @@
// found in the LICENSE file.
#include "chrome/browser/notifications/balloon_host.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/webui/chrome_web_ui_factory.h"
-#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "content/browser/renderer_host/browser_render_process_host.h"
@@ -29,12 +30,20 @@ BalloonHost::BalloonHost(Balloon* balloon)
balloon_(balloon),
initialized_(false),
should_notify_on_disconnect_(false),
- enable_web_ui_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- extension_function_dispatcher_(GetProfile(), this)) {
- CHECK(balloon_);
- site_instance_ = SiteInstance::CreateSiteInstanceForURL(balloon_->profile(),
- GetURL());
+ enable_web_ui_(false) {
+ DCHECK(balloon_);
+
+ // If the notification is for an extension URL, make sure to use the extension
+ // process to render it, so that it can communicate with other views in the
+ // extension.
+ const GURL& balloon_url = balloon_->notification().content_url();
+ if (balloon_url.SchemeIs(chrome::kExtensionScheme)) {
+ site_instance_ =
+ balloon_->profile()->GetExtensionProcessManager()->GetSiteInstanceForURL(
+ balloon_url);
+ } else {
+ site_instance_ = SiteInstance::CreateSiteInstance(balloon_->profile());
+ }
}
void BalloonHost::Shutdown() {
@@ -55,9 +64,7 @@ gfx::NativeView BalloonHost::GetNativeViewOfHost() {
return NULL;
}
-TabContents* BalloonHost::GetAssociatedTabContents() const {
- return NULL;
-}
+TabContents* BalloonHost::associated_tab_contents() const { return NULL; }
const string16& BalloonHost::GetSource() const {
return balloon_->notification().display_source();
@@ -126,16 +133,10 @@ RenderViewHostDelegate::View* BalloonHost::GetViewDelegate() {
}
bool BalloonHost::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(BalloonHost, message)
- IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
+ if (extension_function_dispatcher_.get())
+ return extension_function_dispatcher_->OnMessageReceived(message);
-void BalloonHost::OnRequest(const ExtensionHostMsg_Request_Params& params) {
- extension_function_dispatcher_.Dispatch(params, render_view_host_);
+ return false;
}
// RenderViewHostDelegate::View methods implemented to allow links to
@@ -195,8 +196,24 @@ void BalloonHost::Init() {
DCHECK(!render_view_host_) << "BalloonViewHost already initialized.";
RenderViewHost* rvh = new RenderViewHost(
site_instance_.get(), this, MSG_ROUTING_NONE, NULL);
- if (enable_web_ui_)
+ if (GetProfile()->GetExtensionService()) {
+ extension_function_dispatcher_.reset(
+ ExtensionFunctionDispatcher::Create(
+ rvh, this, balloon_->notification().content_url()));
+ }
+ if (extension_function_dispatcher_.get()) {
+ rvh->AllowBindings(BindingsPolicy::EXTENSION);
+ rvh->set_is_extension_process(true);
+ const Extension* installed_app =
+ GetProfile()->GetExtensionService()->GetInstalledApp(
+ balloon_->notification().content_url());
+ if (installed_app) {
+ GetProfile()->GetExtensionService()->SetInstalledAppForRenderer(
+ rvh->process()->id(), installed_app);
+ }
+ } else if (enable_web_ui_) {
rvh->AllowBindings(BindingsPolicy::WEB_UI);
+ }
// Do platform-specific initialization.
render_view_host_ = rvh;
diff --git a/chrome/browser/notifications/balloon_host.h b/chrome/browser/notifications/balloon_host.h
index 2a03506..9a70e61 100644
--- a/chrome/browser/notifications/balloon_host.h
+++ b/chrome/browser/notifications/balloon_host.h
@@ -44,7 +44,7 @@ class BalloonHost : public RenderViewHostDelegate,
// ExtensionFunctionDispatcher::Delegate overrides.
virtual Browser* GetBrowser();
virtual gfx::NativeView GetNativeViewOfHost();
- virtual TabContents* GetAssociatedTabContents() const;
+ virtual TabContents* associated_tab_contents() const;
RenderViewHost* render_view_host() const { return render_view_host_; }
@@ -137,9 +137,6 @@ class BalloonHost : public RenderViewHostDelegate,
// RenderViewHostDelegate
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- // Message handlers
- void OnRequest(const ExtensionHostMsg_Request_Params& params);
-
// Called to send an event that the balloon has been disconnected from
// a renderer (if should_notify_on_disconnect_ is true).
void NotifyDisconnect();
@@ -161,12 +158,14 @@ class BalloonHost : public RenderViewHostDelegate,
// Common implementations of some RenderViewHostDelegate::View methods.
RenderViewHostDelegateViewHelper delegate_view_helper_;
+ // Handles requests to extension APIs. Will only be non-NULL if we are
+ // rendering a page from an extension.
+ scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+
// A flag to enable Web UI.
bool enable_web_ui_;
NotificationRegistrar registrar_;
-
- ExtensionFunctionDispatcher extension_function_dispatcher_;
};
#endif // CHROME_BROWSER_NOTIFICATIONS_BALLOON_HOST_H_
diff --git a/chrome/browser/sidebar/sidebar_container.cc b/chrome/browser/sidebar/sidebar_container.cc
index d1e4a33..99c69a5 100644
--- a/chrome/browser/sidebar/sidebar_container.cc
+++ b/chrome/browser/sidebar/sidebar_container.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -16,6 +16,7 @@
#include "content/browser/tab_contents/navigation_entry.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/tab_contents_view.h"
+#include "content/common/bindings_policy.h"
#include "googleurl/src/gurl.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -31,6 +32,17 @@ SidebarContainer::SidebarContainer(TabContents* tab,
// Create TabContents for sidebar.
sidebar_contents_.reset(
new TabContents(tab->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL));
+ sidebar_contents_->render_view_host()->set_is_extension_process(true);
+ const Extension* extension = GetExtension();
+ if (extension && extension->is_app()) {
+ ExtensionService* service = tab->profile()->GetExtensionService();
+ if (service) {
+ service->SetInstalledAppForRenderer(
+ sidebar_contents_->render_view_host()->process()->id(), extension);
+ }
+ }
+ sidebar_contents_->render_view_host()->AllowBindings(
+ BindingsPolicy::EXTENSION);
sidebar_contents_->set_delegate(this);
}
diff --git a/chrome/browser/ui/webui/options/extension_settings_handler.cc b/chrome/browser/ui/webui/options/extension_settings_handler.cc
index c1760b7..0aa8434 100644
--- a/chrome/browser/ui/webui/options/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/extension_settings_handler.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_disabled_infobar_delegate.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extension_service.h"
@@ -406,11 +407,13 @@ void ExtensionsDOMHandler::OnIconsLoaded(DictionaryValue* json) {
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED,
+ NotificationService::AllSources());
registrar_.Add(this,
- NotificationType::NAV_ENTRY_COMMITTED,
+ NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED,
NotificationService::AllSources());
registrar_.Add(this,
- NotificationType::RENDER_VIEW_HOST_CREATED,
+ NotificationType::NAV_ENTRY_COMMITTED,
NotificationService::AllSources());
registrar_.Add(this,
NotificationType::RENDER_VIEW_HOST_DELETED,
@@ -721,11 +724,9 @@ void ExtensionsDOMHandler::Observe(NotificationType type,
// we don't know about the views for an extension at EXTENSION_LOADED, but
// if we only listen to EXTENSION_PROCESS_CREATED, we'll miss extensions
// that don't have a process at startup. Similarly, NAV_ENTRY_COMMITTED &
- // RENDER_VIEW_HOST_CREATED because we want to handle both
- // the case of navigating from a non-extension page to an extension page in
- // a TabContents (which will generate NAV_ENTRY_COMMITTED) as well as
- // extension content being shown in popups and balloons (which will generate
- // RENDER_VIEW_CREATED but no NAV_ENTRY_COMMITTED).
+ // EXTENSION_FUNCTION_DISPATCHER_CREATED because we want to handle both
+ // the case of live app pages (which don't have an EFD) and
+ // chrome-extension:// urls which are served in a TabContents.
//
// Doing it this way gets everything but causes the page to be rendered
// more than we need. It doesn't seem to result in any noticeable flicker.
@@ -741,7 +742,8 @@ void ExtensionsDOMHandler::Observe(NotificationType type,
case NotificationType::EXTENSION_PROCESS_CREATED:
case NotificationType::EXTENSION_UNLOADED:
case NotificationType::EXTENSION_UPDATE_DISABLED:
- case NotificationType::RENDER_VIEW_HOST_CREATED:
+ case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED:
+ case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED:
case NotificationType::NAV_ENTRY_COMMITTED:
case NotificationType::BACKGROUND_CONTENTS_NAVIGATED:
case NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED:
diff --git a/chrome/browser/visitedlink/visitedlink_unittest.cc b/chrome/browser/visitedlink/visitedlink_unittest.cc
index 96bcd31..6f58ad7 100644
--- a/chrome/browser/visitedlink/visitedlink_unittest.cc
+++ b/chrome/browser/visitedlink/visitedlink_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -505,7 +505,7 @@ class VisitRelayingRenderProcessHost : public BrowserRenderProcessHost {
Source<RenderProcessHost>(this), NotificationService::NoDetails());
}
- virtual bool Init(bool is_accessibility_enabled) {
+ virtual bool Init(bool is_accessibility_enabled, bool is_extension_process) {
return true;
}
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc
index 13339c3..a2bb8c0 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -35,8 +35,7 @@ using WebKit::WebFrame;
using WebKit::WebSecurityPolicy;
using WebKit::WebString;
-ExtensionDispatcher::ExtensionDispatcher()
- : is_webkit_initialized_(false) {
+ExtensionDispatcher::ExtensionDispatcher() {
std::string type_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kProcessType);
is_extension_process_ = type_str == switches::kExtensionProcess ||
@@ -89,17 +88,6 @@ void ExtensionDispatcher::WebKitInitialized() {
RegisterExtension(EventBindings::Get(this), true);
RegisterExtension(RendererExtensionBindings::Get(this), true);
RegisterExtension(ExtensionApiTestV8Extension::Get(), true);
-
- // Initialize host permissions for any extensions that were activated before
- // WebKit was initialized.
- for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
- iter != active_extension_ids_.end(); ++iter) {
- const Extension* extension = extensions_.GetByID(*iter);
- if (extension)
- InitHostPermissions(extension);
- }
-
- is_webkit_initialized_ = true;
}
void ExtensionDispatcher::IdleNotification() {
@@ -214,11 +202,6 @@ void ExtensionDispatcher::OnActivateExtension(
if (!extension)
return;
- if (is_webkit_initialized_)
- InitHostPermissions(extension);
-}
-
-void ExtensionDispatcher::InitHostPermissions(const Extension* extension) {
if (extension->HasApiPermission(Extension::kManagementPermission)) {
WebSecurityPolicy::addOriginAccessWhitelistEntry(
extension->url(),
@@ -227,7 +210,13 @@ void ExtensionDispatcher::InitHostPermissions(const Extension* extension) {
false);
}
- const URLPatternList& permissions = extension->host_permissions();
+ SetHostPermissions(extension->url(),
+ extension->host_permissions());
+}
+
+void ExtensionDispatcher::SetHostPermissions(
+ const GURL& extension_url,
+ const std::vector<URLPattern>& permissions) {
for (size_t i = 0; i < permissions.size(); ++i) {
const char* schemes[] = {
chrome::kHttpScheme,
@@ -238,7 +227,7 @@ void ExtensionDispatcher::InitHostPermissions(const Extension* extension) {
for (size_t j = 0; j < arraysize(schemes); ++j) {
if (permissions[i].MatchesScheme(schemes[j])) {
WebSecurityPolicy::addOriginAccessWhitelistEntry(
- extension->url(),
+ extension_url,
WebString::fromUTF8(schemes[j]),
WebString::fromUTF8(permissions[i].host()),
permissions[i].match_subdomains());
diff --git a/chrome/renderer/extensions/extension_dispatcher.h b/chrome/renderer/extensions/extension_dispatcher.h
index bce3c0f..c966d37 100644
--- a/chrome/renderer/extensions/extension_dispatcher.h
+++ b/chrome/renderer/extensions/extension_dispatcher.h
@@ -81,8 +81,9 @@ class ExtensionDispatcher : public RenderProcessObserver {
// extension is for Chrome Extensions only.
void RegisterExtension(v8::Extension* extension, bool restrict_to_extensions);
- // Sets up the host permissions for |extension|.
- void InitHostPermissions(const Extension* extension);
+ // Sets the host permissions for a particular extension.
+ void SetHostPermissions(const GURL& extension_url,
+ const std::vector<URLPattern>& permissions);
// True if this renderer is running extensions.
bool is_extension_process_;
@@ -107,9 +108,6 @@ class ExtensionDispatcher : public RenderProcessObserver {
// The extensions that are active in this process.
std::set<std::string> active_extension_ids_;
- // True once WebKit has been initialized (and it is therefore safe to poke).
- bool is_webkit_initialized_;
-
DISALLOW_COPY_AND_ASSIGN(ExtensionDispatcher);
};
diff --git a/content/browser/content_browser_client.cc b/content/browser/content_browser_client.cc
index 901097e..84603af 100644
--- a/content/browser/content_browser_client.cc
+++ b/content/browser/content_browser_client.cc
@@ -14,6 +14,11 @@ void ContentBrowserClient::RenderViewHostCreated(
RenderViewHost* render_view_host) {
}
+void ContentBrowserClient::PreCreateRenderView(RenderViewHost* render_view_host,
+ Profile* profile,
+ const GURL& url) {
+}
+
void ContentBrowserClient::BrowserRenderProcessHostCreated(
BrowserRenderProcessHost* host) {
}
diff --git a/content/browser/content_browser_client.h b/content/browser/content_browser_client.h
index 7772188..2de7751 100644
--- a/content/browser/content_browser_client.h
+++ b/content/browser/content_browser_client.h
@@ -34,7 +34,14 @@ class ContentBrowserClient {
// Notifies that a new RenderHostView has been created.
virtual void RenderViewHostCreated(RenderViewHost* render_view_host);
- // Notifies that a BrowserRenderProcessHost has been created.
+ // Initialize a RenderViewHost before its CreateRenderView method is called.
+ virtual void PreCreateRenderView(RenderViewHost* render_view_host,
+ Profile* profile,
+ const GURL& url);
+
+ // Notifies that a BrowserRenderProcessHost has been created. This is called
+ // before the content layer adds its own BrowserMessageFilters, so that the
+ // embedder's IPC filters have priority.
virtual void BrowserRenderProcessHostCreated(BrowserRenderProcessHost* host);
// Notifies that a WorkerProcessHost has been created.
diff --git a/content/browser/renderer_host/browser_render_process_host.cc b/content/browser/renderer_host/browser_render_process_host.cc
index 4868e89..aa5808f 100644
--- a/content/browser/renderer_host/browser_render_process_host.cc
+++ b/content/browser/renderer_host/browser_render_process_host.cc
@@ -192,7 +192,7 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile)
base::TimeDelta::FromSeconds(5),
this, &BrowserRenderProcessHost::ClearTransportDIBCache)),
accessibility_enabled_(false),
- is_initialized_(false) {
+ extension_process_(false) {
widget_helper_ = new RenderWidgetHelper();
WebCacheManager::GetInstance()->Add(id());
@@ -239,7 +239,8 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() {
ClearTransportDIBCache();
}
-bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) {
+bool BrowserRenderProcessHost::Init(
+ bool is_accessibility_enabled, bool is_extensions_process) {
// calling Init() more than once does nothing, this makes it more convenient
// for the view host which may not be sure in some cases
if (channel_.get())
@@ -247,6 +248,10 @@ bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) {
accessibility_enabled_ = is_accessibility_enabled;
+ // It is possible for an extension process to be reused for non-extension
+ // content, e.g. if an extension calls window.open.
+ extension_process_ = extension_process_ || is_extensions_process;
+
CommandLine::StringType renderer_prefix;
#if defined(OS_POSIX)
// A command prefix is something prepended to the command line of the spawned
@@ -327,7 +332,6 @@ bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) {
fast_shutdown_started_ = false;
}
- is_initialized_ = true;
return true;
}
@@ -466,8 +470,8 @@ void BrowserRenderProcessHost::AppendRendererCommandLine(
// Extensions use a special pseudo-process type to make them distinguishable,
// even though they're just renderers.
command_line->AppendSwitchASCII(switches::kProcessType,
- is_extension_process_ ? switches::kExtensionProcess :
- switches::kRendererProcess);
+ extension_process_ ? switches::kExtensionProcess :
+ switches::kRendererProcess);
if (logging::DialogsAreSuppressed())
command_line->AppendSwitch(switches::kNoErrorDialogs);
@@ -758,13 +762,8 @@ void BrowserRenderProcessHost::ClearTransportDIBCache() {
bool BrowserRenderProcessHost::Send(IPC::Message* msg) {
if (!channel_.get()) {
- if (!is_initialized_) {
- queued_messages_.push(msg);
- return true;
- } else {
- delete msg;
- return false;
- }
+ delete msg;
+ return false;
}
if (child_process_launcher_.get() && child_process_launcher_->IsStarting()) {
@@ -853,15 +852,15 @@ void BrowserRenderProcessHost::OnChannelError() {
if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
- is_extension_process_ ? 2 : 1);
+ extension_process_ ? 2 : 1);
}
if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
- is_extension_process_ ? 2 : 1);
+ extension_process_ ? 2 : 1);
}
- RendererClosedDetails details(status, exit_code, is_extension_process_);
+ RendererClosedDetails details(status, exit_code, extension_process_);
NotificationService::current()->Notify(
NotificationType::RENDERER_PROCESS_CLOSED,
Source<RenderProcessHost>(this),
diff --git a/content/browser/renderer_host/browser_render_process_host.h b/content/browser/renderer_host/browser_render_process_host.h
index fb46c82..3f7a23c 100644
--- a/content/browser/renderer_host/browser_render_process_host.h
+++ b/content/browser/renderer_host/browser_render_process_host.h
@@ -47,7 +47,7 @@ class BrowserRenderProcessHost : public RenderProcessHost,
~BrowserRenderProcessHost();
// RenderProcessHost implementation (public portion).
- virtual bool Init(bool is_accessibility_enabled);
+ virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process);
virtual int GetNextRoutingID();
virtual void CancelResourceRequests(int render_widget_id);
virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params);
@@ -131,9 +131,9 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// True if this prcoess should have accessibility enabled;
bool accessibility_enabled_;
- // True after Init() has been called. We can't just check channel_ because we
- // also reset that in the case of process termination.
- bool is_initialized_;
+ // True iff this process is being used as an extension process. Not valid
+ // when running in single-process mode.
+ bool extension_process_;
// Used to launch and terminate the process without blocking the UI thread.
scoped_ptr<ChildProcessLauncher> child_process_launcher_;
diff --git a/content/browser/renderer_host/mock_render_process_host.cc b/content/browser/renderer_host/mock_render_process_host.cc
index dec107a..104395f 100644
--- a/content/browser/renderer_host/mock_render_process_host.cc
+++ b/content/browser/renderer_host/mock_render_process_host.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -23,7 +23,8 @@ MockRenderProcessHost::~MockRenderProcessHost() {
factory_->Remove(this);
}
-bool MockRenderProcessHost::Init(bool is_accessibility_enabled) {
+bool MockRenderProcessHost::Init(
+ bool is_accessibility_enabled, bool is_extensions_process) {
return true;
}
diff --git a/content/browser/renderer_host/mock_render_process_host.h b/content/browser/renderer_host/mock_render_process_host.h
index a6804a1..0e7656c 100644
--- a/content/browser/renderer_host/mock_render_process_host.h
+++ b/content/browser/renderer_host/mock_render_process_host.h
@@ -36,7 +36,7 @@ class MockRenderProcessHost : public RenderProcessHost {
int bad_msg_count() const { return bad_msg_count_; }
// RenderProcessHost implementation (public portion).
- virtual bool Init(bool is_accessibility_enabled);
+ virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process);
virtual int GetNextRoutingID();
virtual void CancelResourceRequests(int render_widget_id);
virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params);
diff --git a/content/browser/renderer_host/render_process_host.cc b/content/browser/renderer_host/render_process_host.cc
index 5466004..379ce99 100644
--- a/content/browser/renderer_host/render_process_host.cc
+++ b/content/browser/renderer_host/render_process_host.cc
@@ -94,7 +94,6 @@ RenderProcessHost::RenderProcessHost(Profile* profile)
: max_page_id_(-1),
fast_shutdown_started_(false),
deleting_soon_(false),
- is_extension_process_(false),
pending_views_(0),
id_(ChildProcessInfo::GenerateChildProcessUniqueId()),
profile_(profile),
diff --git a/content/browser/renderer_host/render_process_host.h b/content/browser/renderer_host/render_process_host.h
index 9d3b8fc..b43fbe2 100644
--- a/content/browser/renderer_host/render_process_host.h
+++ b/content/browser/renderer_host/render_process_host.h
@@ -88,9 +88,6 @@ class RenderProcessHost : public IPC::Channel::Sender,
sudden_termination_allowed_ = enabled;
}
- bool is_extension_process() const { return is_extension_process_; }
- void mark_is_extension_process() { is_extension_process_ = true; }
-
// Used for refcounting, each holder of this object must Attach and Release
// just like it would for a COM object. This object should be allocated on
// the heap; when no listeners own it any more, it will delete itself.
@@ -166,7 +163,8 @@ class RenderProcessHost : public IPC::Channel::Sender,
// be called once before the object can be used, but can be called after
// that with no effect. Therefore, if the caller isn't sure about whether
// the process has been created, it should just call Init().
- virtual bool Init(bool is_accessibility_enabled) = 0;
+ virtual bool Init(
+ bool is_accessibility_enabled, bool is_extensions_process) = 0;
// Gets the next available routing id.
virtual int GetNextRoutingID() = 0;
@@ -284,10 +282,6 @@ class RenderProcessHost : public IPC::Channel::Sender,
// True if we've posted a DeleteTask and will be deleted soon.
bool deleting_soon_;
- // True iff this process is being used as an extension process. Not valid
- // when running in single-process mode.
- bool is_extension_process_;
-
// The count of currently swapped out but pending RenderViews. We have
// started to swap these in, so the renderer process should not exit if
// this count is non-zero.
diff --git a/content/browser/renderer_host/render_view_host.cc b/content/browser/renderer_host/render_view_host.cc
index c74ac5e..47e5457 100644
--- a/content/browser/renderer_host/render_view_host.cc
+++ b/content/browser/renderer_host/render_view_host.cc
@@ -102,6 +102,7 @@ RenderViewHost::RenderViewHost(SiteInstance* instance,
are_javascript_messages_suppressed_(false),
sudden_termination_allowed_(false),
session_storage_namespace_(session_storage),
+ is_extension_process_(false),
save_accessibility_tree_for_testing_(false),
render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING) {
if (!session_storage_namespace_) {
@@ -113,11 +114,6 @@ RenderViewHost::RenderViewHost(SiteInstance* instance,
DCHECK(delegate_);
content::GetContentClient()->browser()->RenderViewHostCreated(this);
-
- NotificationService::current()->Notify(
- NotificationType::RENDER_VIEW_HOST_CREATED,
- Source<RenderViewHost>(this),
- NotificationService::NoDetails());
}
RenderViewHost::~RenderViewHost() {
@@ -143,7 +139,7 @@ bool RenderViewHost::CreateRenderView(const string16& frame_name) {
// initialized it) or may not (we have our own process or the old process
// crashed) have been initialized. Calling Init multiple times will be
// ignored, so this is safe.
- if (!process()->Init(renderer_accessible()))
+ if (!process()->Init(renderer_accessible(), is_extension_process_))
return false;
DCHECK(process()->HasConnection());
DCHECK(process()->profile());
@@ -156,6 +152,10 @@ bool RenderViewHost::CreateRenderView(const string16& frame_name) {
if (BindingsPolicy::is_extension_enabled(enabled_bindings_)) {
ChildProcessSecurityPolicy::GetInstance()->GrantExtensionBindings(
process()->id());
+
+ // Extensions may have permission to access chrome:// URLs.
+ ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
+ process()->id(), chrome::kChromeUIScheme);
}
renderer_initialized_ = true;
diff --git a/content/browser/renderer_host/render_view_host.h b/content/browser/renderer_host/render_view_host.h
index b29f2ed..bfd7bf85 100644
--- a/content/browser/renderer_host/render_view_host.h
+++ b/content/browser/renderer_host/render_view_host.h
@@ -314,6 +314,12 @@ class RenderViewHost : public RenderWidgetHost {
// RenderView. See BindingsPolicy for details.
int enabled_bindings() const { return enabled_bindings_; }
+ // See variable comment.
+ bool is_extension_process() const { return is_extension_process_; }
+ void set_is_extension_process(bool is_extension_process) {
+ is_extension_process_ = is_extension_process;
+ }
+
// Sets a property with the given name and value on the Web UI binding object.
// Must call AllowWebUIBindings() on this renderer first.
void SetWebUIProperty(const std::string& name, const std::string& value);
@@ -593,6 +599,10 @@ class RenderViewHost : public RenderWidgetHost {
// The session storage namespace to be used by the associated render view.
scoped_refptr<SessionStorageNamespace> session_storage_namespace_;
+ // Whether this render view will get extension api bindings. This controls
+ // what process type we use.
+ bool is_extension_process_;
+
// Whether the accessibility tree should be saved, for unit testing.
bool save_accessibility_tree_for_testing_;
diff --git a/content/browser/tab_contents/render_view_host_manager.cc b/content/browser/tab_contents/render_view_host_manager.cc
index 442e91c8..22ae236 100644
--- a/content/browser/tab_contents/render_view_host_manager.cc
+++ b/content/browser/tab_contents/render_view_host_manager.cc
@@ -506,6 +506,11 @@ bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host,
if (pending_web_ui_.get())
render_view_host->AllowBindings(pending_web_ui_->bindings());
+ // Give the embedder a chance to initialize the render view.
+ Profile* profile = delegate_->GetControllerForRenderManager().profile();
+ content::GetContentClient()->browser()->PreCreateRenderView(
+ render_view_host, profile, entry.url());
+
return delegate_->CreateRenderViewForRenderManager(render_view_host);
}
diff --git a/content/common/notification_type.h b/content/common/notification_type.h
index c7e4d6a..850b887 100644
--- a/content/common/notification_type.h
+++ b/content/common/notification_type.h
@@ -459,10 +459,6 @@ class NotificationType {
// Used only in testing.
RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK,
- // Sent from RenderViewHost constructor. The source is the RenderViewHost,
- // the details unused.
- RENDER_VIEW_HOST_CREATED,
-
// Sent from ~RenderViewHost. The source is the RenderViewHost, the details
// unused.
RENDER_VIEW_HOST_DELETED,
@@ -869,6 +865,18 @@ class NotificationType {
// Extension, and the source is a Profile.
EXTENSION_USER_SCRIPTS_UPDATED,
+ // Sent after a new ExtensionFunctionDispatcher is created. The details are
+ // an ExtensionFunctionDispatcher* and the source is a Profile*. This is
+ // similar in timing to EXTENSION_HOST_CREATED, but also fires when an
+ // extension view which is hosted in TabContents* is created.
+ EXTENSION_FUNCTION_DISPATCHER_CREATED,
+
+ // Sent before an ExtensionHost is destroyed. The details are
+ // an ExtensionFunctionDispatcher* and the source is a Profile*. This is
+ // similar in timing to EXTENSION_HOST_DESTROYED, but also fires when an
+ // extension view which is hosted in TabContents* is destroyed.
+ EXTENSION_FUNCTION_DISPATCHER_DESTROYED,
+
// Sent after a new ExtensionHost is created. The details are
// an ExtensionHost* and the source is an ExtensionProcessManager*.
EXTENSION_HOST_CREATED,