Re-land r84928: Move EFD to ExtensionTabHelper.

BUG=80308
[email protected]

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85242 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index b7ce694..8efed98 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -26,13 +26,19 @@
 #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"
@@ -42,6 +48,65 @@
 #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(
@@ -50,24 +115,8 @@
   new DesktopNotificationHandler(render_view_host);
   new DevToolsHandler(render_view_host);
   new ExtensionMessageHandler(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);
-    }
-  }
+  InitRenderViewHostForExtensions(render_view_host);
 }
 
 void ChromeContentBrowserClient::BrowserRenderProcessHostCreated(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index ee81fd389..2ba3e24 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -13,9 +13,6 @@
 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 6f23fe8..6d89d373 100644
--- a/chrome/browser/extensions/extension_bookmark_manager_api.cc
+++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc
@@ -365,12 +365,13 @@
   EXTENSION_FUNCTION_VALIDATE(
       GetNodesFromArguments(model, args_.get(), 0, &nodes));
 
-  if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() ==
+  if (render_view_host_->delegate()->GetRenderViewType() ==
       ViewType::TAB_CONTENTS) {
-    ExtensionWebUI* web_ui =
-        static_cast<ExtensionWebUI*>(dispatcher()->delegate());
-    bookmark_utils::DragBookmarks(
-        profile(), nodes, web_ui->tab_contents()->GetNativeView());
+    TabContents* tab_contents =
+        dispatcher()->delegate()->GetAssociatedTabContents();
+    CHECK(tab_contents);
+    bookmark_utils::DragBookmarks(profile(), nodes,
+                                  tab_contents->GetNativeView());
 
     return true;
   } else {
@@ -406,10 +407,14 @@
   else
     drop_index = drop_parent->child_count();
 
-  if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() ==
+  if (render_view_host_->delegate()->GetRenderViewType() ==
       ViewType::TAB_CONTENTS) {
+    TabContents* tab_contents =
+        dispatcher()->delegate()->GetAssociatedTabContents();
+    CHECK(tab_contents);
     ExtensionWebUI* web_ui =
-        static_cast<ExtensionWebUI*>(dispatcher()->delegate());
+        static_cast<ExtensionWebUI*>(tab_contents->web_ui());
+    CHECK(web_ui);
     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 1777e79..37a814fc 100644
--- a/chrome/browser/extensions/extension_bookmarks_module.cc
+++ b/chrome/browser/extensions/extension_bookmarks_module.cc
@@ -856,7 +856,7 @@
   file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html"));
 
   TabContents* tab_contents = dispatcher()->delegate()->
-      associated_tab_contents();
+      GetAssociatedTabContents();
 
   // |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 80073b4..a818a83 100644
--- a/chrome/browser/extensions/extension_file_browser_private_api.cc
+++ b/chrome/browser/extensions/extension_file_browser_private_api.cc
@@ -352,8 +352,7 @@
 }
 
 bool RequestLocalFileSystemFunction::RunImpl() {
-  if (!dispatcher() || !dispatcher()->render_view_host() ||
-      !dispatcher()->render_view_host()->process())
+  if (!dispatcher() || !render_view_host() || !render_view_host()->process())
     return false;
 
   BrowserThread::PostTask(
@@ -361,7 +360,7 @@
       NewRunnableMethod(this,
           &RequestLocalFileSystemFunction::RequestOnFileThread,
           source_url_,
-          dispatcher()->render_view_host()->process()->id()));
+          render_view_host()->process()->id()));
   // Will finish asynchronously.
   return true;
 }
@@ -679,7 +678,7 @@
           new ExecuteTasksFileSystemCallbackDispatcher(
               this,
               profile(),
-              dispatcher()->render_view_host()->process()->id(),
+              render_view_host()->process()->id(),
               source_url,
               GetExtension(),
               task_id,
@@ -805,13 +804,13 @@
 
 
 int32 FileDialogFunction::GetTabId() const {
-  return dispatcher()->delegate()->associated_tab_contents()->
+  return dispatcher()->delegate()->GetAssociatedTabContents()->
     controller().session_id().id();
 }
 
 const FileDialogFunction::Callback& FileDialogFunction::GetCallback() const {
   if (!dispatcher() || !dispatcher()->delegate() ||
-      !dispatcher()->delegate()->associated_tab_contents()) {
+      !dispatcher()->delegate()->GetAssociatedTabContents()) {
     return Callback::null();
   }
   return Callback::Find(GetTabId());
@@ -819,7 +818,7 @@
 
 void FileDialogFunction::CloseDialog(HtmlDialogView* dialog) {
   DCHECK(dialog);
-  TabContents* contents = dispatcher()->delegate()->associated_tab_contents();
+  TabContents* contents = dispatcher()->delegate()->GetAssociatedTabContents();
   if (contents)
     dialog->CloseContents(contents);
 }
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 9f0d065..f390d72 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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,6 +9,31 @@
 #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),
@@ -21,6 +46,11 @@
 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);
@@ -28,7 +58,7 @@
 }
 
 Browser* ExtensionFunction::GetCurrentBrowser() {
-  return dispatcher()->GetCurrentBrowser(include_incognito_);
+  return dispatcher()->GetCurrentBrowser(render_view_host_, include_incognito_);
 }
 
 AsyncExtensionFunction::AsyncExtensionFunction()
@@ -61,12 +91,28 @@
 }
 
 void AsyncExtensionFunction::SendResponse(bool success) {
-  if (!dispatcher())
+  if (!render_view_host_ || !dispatcher())
     return;
   if (bad_message_) {
-    dispatcher()->HandleBadMessage(this);
+    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);
   } else {
-    dispatcher()->SendResponse(this, success);
+    NOTREACHED();
+    UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD"));
+    base::KillProcess(render_view_host_->process()->GetHandle(),
+                      ResultCodes::KILLED_BAD_MESSAGE, false);
   }
 }
 
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index 7913703..9ec4ea875 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -12,6 +12,9 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include "content/browser/browser_thread.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
 
 class ExtensionFunctionDispatcher;
 class ListValue;
@@ -37,10 +40,14 @@
 
 // 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,
+                                        BrowserThread::DeleteOnUIThread> {
  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_; }
@@ -56,6 +63,9 @@
   }
   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;
 
@@ -102,8 +112,6 @@
  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.
@@ -130,6 +138,9 @@
   // 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_;
 
@@ -158,6 +169,26 @@
   // 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);
 };
 
@@ -204,6 +235,13 @@
   // 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 6a69d42c..8a27836 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -30,7 +30,6 @@
 #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"
@@ -52,9 +51,6 @@
 #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"
@@ -385,71 +381,19 @@
   FactoryRegistry::GetInstance()->ResetFunctions();
 }
 
-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),
+ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile,
+                                                         Delegate* delegate)
+  : profile_(profile),
     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(
-    bool include_incognito) {
+    RenderViewHost* render_view_host, bool include_incognito) {
   Browser* browser = delegate_->GetBrowser();
 
   // If the delegate has an associated browser, that is always the right answer.
@@ -461,7 +405,7 @@
   // 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,
@@ -473,88 +417,84 @@
   return browser;
 }
 
-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;
-}
+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;
+  }
 
-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."));
+  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;
+  }
+
+  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);
     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::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_;
+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."));
 }
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index 9f91d9d..d3b8d1c 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -11,7 +11,6 @@
 
 #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;
@@ -27,9 +26,19 @@
 typedef ExtensionFunction* (*ExtensionFunctionFactory)();
 
 // ExtensionFunctionDispatcher receives requests to execute functions from
-// Chromium extensions running in a RenderViewHost and dispatches them to the
+// Chrome extensions running in a RenderViewHost and dispatches them to the
 // appropriate handler. It lives entirely on the UI thread.
-class ExtensionFunctionDispatcher : public IPC::Channel::Listener {
+//
+// 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 {
  public:
   class Delegate {
    public:
@@ -45,7 +54,7 @@
     // 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* associated_tab_contents() const = 0;
+    virtual TabContents* GetAssociatedTabContents() const = 0;
 
    protected:
     virtual ~Delegate() {}
@@ -76,21 +85,19 @@
   // Resets all functions to their initial implementation.
   static void ResetFunctions();
 
-  // 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);
+  // 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);
 
   ~ExtensionFunctionDispatcher();
 
   Delegate* delegate() { return delegate_; }
 
-  // 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);
+  // Message handlers.
+  void Dispatch(const ExtensionHostMsg_Request_Params& params,
+                RenderViewHost* sender);
 
   // Returns the current browser. Callers should generally prefer
   // ExtensionFunction::GetCurrentBrowser() over this method, as that one
@@ -98,46 +105,20 @@
   //
   // See the comments for ExtensionFunction::GetCurrentBrowser() for more
   // details.
-  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_; }
+  Browser* GetCurrentBrowser(RenderViewHost* render_view_host,
+                             bool include_incognito);
 
   // The profile that this dispatcher is associated with.
-  Profile* profile();
-
-  // The RenderViewHost this dispatcher is associated with.
-  RenderViewHost* render_view_host() { return render_view_host_; }
+  Profile* profile() { return profile_; }
 
  private:
-  ExtensionFunctionDispatcher(RenderViewHost* render_view_host,
-                              Delegate* delegate,
-                              const Extension* extension,
-                              const GURL& url);
+  // Helper to send an access denied error to the requesting render view.
+  void SendAccessDenied(RenderViewHost* render_view_host, int request_id);
 
-  // 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 af3eda6..8399a338 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -28,6 +28,7 @@
 #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"
@@ -131,17 +132,13 @@
       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);
 
@@ -182,7 +179,7 @@
 #endif
 }
 
-TabContents* ExtensionHost::associated_tab_contents() const {
+TabContents* ExtensionHost::GetAssociatedTabContents() const {
   return associated_tab_contents_;
 }
 
@@ -314,6 +311,9 @@
   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,29 +327,7 @@
   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() {
@@ -466,7 +444,8 @@
     return platform_util::GetTopLevel(native_view);
 
   // Otherwise, try the active tab's view.
-  Browser* browser = extension_function_dispatcher_->GetCurrentBrowser(true);
+  Browser* browser = extension_function_dispatcher_.GetCurrentBrowser(
+      render_view_host_, true);
   if (browser) {
     TabContents* active_tab = browser->GetSelectedTabContents();
     if (active_tab)
@@ -508,7 +487,7 @@
 RendererPreferences ExtensionHost::GetRendererPrefs(Profile* profile) const {
   RendererPreferences preferences;
 
-  TabContents* associated_contents = associated_tab_contents();
+  TabContents* associated_contents = GetAssociatedTabContents();
   if (associated_contents)
     preferences =
         static_cast<RenderViewHostDelegate*>(associated_contents)->
@@ -562,7 +541,7 @@
       params.window_container_type,
       params.frame_name);
 
-  TabContents* associated_contents = associated_tab_contents();
+  TabContents* associated_contents = GetAssociatedTabContents();
   if (associated_contents && associated_contents->delegate())
     associated_contents->delegate()->TabContentsCreated(new_contents);
 }
@@ -617,7 +596,7 @@
   // 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 = associated_tab_contents();
+  TabContents* associated_contents = GetAssociatedTabContents();
   if (associated_contents &&
       associated_contents->profile() == contents->profile()) {
     associated_contents->AddNewContents(
@@ -775,19 +754,19 @@
 }
 
 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_;
 }
@@ -796,13 +775,6 @@
   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(
@@ -833,5 +805,5 @@
   if (file_select_helper_.get() == NULL)
     file_select_helper_.reset(new FileSelectHelper(profile()));
   file_select_helper_->RunFileChooser(render_view_host_,
-                                      associated_tab_contents(), params);
+                                      GetAssociatedTabContents(), params);
 }
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index 116e37d..a02d774 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -86,7 +86,7 @@
   ViewType::Type extension_host_type() const { return extension_host_type_; }
 
   // ExtensionFunctionDispatcher::Delegate
-  virtual TabContents* associated_tab_contents() const;
+  virtual TabContents* GetAssociatedTabContents() const;
   void set_associated_tab_contents(TabContents* associated_tab_contents) {
     associated_tab_contents_ = associated_tab_contents;
   }
@@ -230,6 +230,7 @@
 
   // 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 +276,7 @@
 
   NotificationRegistrar registrar_;
 
-  scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+  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 6f44f6c..8a1caa5 100644
--- a/chrome/browser/extensions/extension_tab_helper.cc
+++ b/chrome/browser/extensions/extension_tab_helper.cc
@@ -6,12 +6,15 @@
 
 #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"
@@ -19,6 +22,8 @@
 ExtensionTabHelper::ExtensionTabHelper(TabContentsWrapper* wrapper)
     : TabContentsObserver(wrapper->tab_contents()),
       extension_app_(NULL),
+      ALLOW_THIS_IN_INITIALIZER_LIST(
+          extension_function_dispatcher_(wrapper->profile(), this)),
       wrapper_(wrapper) {
 }
 
@@ -113,6 +118,7 @@
                         OnDidGetApplicationInfo)
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_InstallApplication,
                         OnInstallApplication)
+    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -131,6 +137,12 @@
     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();
 
@@ -161,3 +173,37 @@
     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 46b0348..8a4b51e 100644
--- a/chrome/browser/extensions/extension_tab_helper.h
+++ b/chrome/browser/extensions/extension_tab_helper.h
@@ -7,6 +7,7 @@
 #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"
@@ -17,6 +18,7 @@
 
 // Per-tab extension helper. Also handles non-extension apps.
 class ExtensionTabHelper : public TabContentsObserver,
+                           public ExtensionFunctionDispatcher::Delegate,
                            public ImageLoadingTracker::Observer {
  public:
   explicit ExtensionTabHelper(TabContentsWrapper* wrapper);
@@ -77,9 +79,16 @@
       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:
 
@@ -101,6 +110,9 @@
   // 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 a43d894..97654bf 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -793,7 +793,7 @@
 bool GetCurrentTabFunction::RunImpl() {
   DCHECK(dispatcher());
 
-  TabContents* contents = dispatcher()->delegate()->associated_tab_contents();
+  TabContents* contents = dispatcher()->delegate()->GetAssociatedTabContents();
   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 e398c468..32eb5cbc 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -24,11 +24,9 @@
 #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"
@@ -140,7 +138,10 @@
   // component apps like bookmark manager.
   should_hide_url_ = !extension->is_hosted_app();
 
-  bindings_ = BindingsPolicy::EXTENSION;
+  // The base class defaults to enabling web ui bindings, but we don't need
+  // those.
+  bindings_ = 0;
+
   // Bind externalHost to Extension WebUI loaded in Chrome Frame.
   const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
   if (browser_command_line.HasSwitch(switches::kChromeFrame))
@@ -155,86 +156,23 @@
       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_function_dispatcher_->extension_id() ==
-      extension_misc::kBookmarkManagerId) {
+  if (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;
   }
 }
 
-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();
-}
+ExtensionWebUI::~ExtensionWebUI() {}
 
 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 3a3a80b..4aad170 100644
--- a/chrome/browser/extensions/extension_web_ui.h
+++ b/chrome/browser/extensions/extension_web_ui.h
@@ -10,11 +10,9 @@
 
 #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;
@@ -22,15 +20,12 @@
 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,
-      public ExtensionFunctionDispatcher::Delegate {
+class ExtensionWebUI : public WebUI {
  public:
   static const char kExtensionURLOverrides[];
 
@@ -38,21 +33,6 @@
 
   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();
 
@@ -87,15 +67,6 @@
                                            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 8dbf650..7c46cff3 100644
--- a/chrome/browser/extensions/extension_webstore_private_api.cc
+++ b/chrome/browser/extensions/extension_webstore_private_api.cc
@@ -461,7 +461,7 @@
   // install flow. The above call to SetWhitelistedInstallId will bypass the
   // normal permissions install dialog.
   NavigationController& controller =
-      dispatcher()->delegate()->associated_tab_contents()->controller();
+      dispatcher()->delegate()->GetAssociatedTabContents()->controller();
   controller.LoadURL(url, source_url(), PageTransition::LINK);
 
   return true;
@@ -519,7 +519,7 @@
   // 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()->associated_tab_contents();
+  TabContents* tab = dispatcher()->delegate()->GetAssociatedTabContents();
   if (!tab)
     return false;
 
diff --git a/chrome/browser/extensions/extensions_quota_service_unittest.cc b/chrome/browser/extensions/extensions_quota_service_unittest.cc
index 72958a9..63eedb1 100644
--- a/chrome/browser/extensions/extensions_quota_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_quota_service_unittest.cc
@@ -95,11 +95,17 @@
 class ExtensionsQuotaServiceTest : public testing::Test {
  public:
   ExtensionsQuotaServiceTest()
-      : extension_a_("a"), extension_b_("b"), extension_c_("c") {}
+      : extension_a_("a"),
+        extension_b_("b"),
+        extension_c_("c"),
+        loop_(),
+        ui_thread_(BrowserThread::UI, &loop_) {
+  }
   virtual void SetUp() {
     service_.reset(new ExtensionsQuotaService());
   }
   virtual void TearDown() {
+    loop_.RunAllPending();
     service_.reset();
   }
  protected:
@@ -107,6 +113,8 @@
   std::string extension_b_;
   std::string extension_c_;
   scoped_ptr<ExtensionsQuotaService> service_;
+  MessageLoop loop_;
+  BrowserThread ui_thread_;
 };
 
 class QuotaLimitHeuristicTest : public testing::Test {
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 8022dc4..37e4fd9 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -20,7 +20,6 @@
 #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"
@@ -300,15 +299,13 @@
       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::EXTENSION_FUNCTION_DISPATCHER_DESTROYED,
-      NotificationService::AllSources());
   registrar_.Add(this,
       NotificationType::NAV_ENTRY_COMMITTED,
       NotificationService::AllSources());
   registrar_.Add(this,
+      NotificationType::RENDER_VIEW_HOST_CREATED,
+      NotificationService::AllSources());
+  registrar_.Add(this,
       NotificationType::RENDER_VIEW_HOST_DELETED,
       NotificationService::AllSources());
   registrar_.Add(this,
@@ -631,9 +628,11 @@
     // 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 &
-    // 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.
+    // 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).
     //
     // 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.
@@ -649,8 +648,7 @@
     case NotificationType::EXTENSION_PROCESS_CREATED:
     case NotificationType::EXTENSION_UNLOADED:
     case NotificationType::EXTENSION_UPDATE_DISABLED:
-    case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED:
-    case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED:
+    case NotificationType::RENDER_VIEW_HOST_CREATED:
     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 ea1c8345..074e42d 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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 @@
         }
         TabContents* contents = host_delegate->GetAsTabContents();
         if (!contents) {
-          if (host->is_extension_process()) {
+          if (host->process()->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 3d600a0..7219be0 100644
--- a/chrome/browser/notifications/balloon_host.cc
+++ b/chrome/browser/notifications/balloon_host.cc
@@ -3,14 +3,13 @@
 // 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"
@@ -30,20 +29,12 @@
       balloon_(balloon),
       initialized_(false),
       should_notify_on_disconnect_(false),
-      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());
-  }
+      enable_web_ui_(false),
+      ALLOW_THIS_IN_INITIALIZER_LIST(
+          extension_function_dispatcher_(GetProfile(), this)) {
+  CHECK(balloon_);
+  site_instance_ = SiteInstance::CreateSiteInstanceForURL(balloon_->profile(),
+                                                          GetURL());
 }
 
 void BalloonHost::Shutdown() {
@@ -64,7 +55,9 @@
   return NULL;
 }
 
-TabContents* BalloonHost::associated_tab_contents() const { return NULL; }
+TabContents* BalloonHost::GetAssociatedTabContents() const {
+  return NULL;
+}
 
 const string16& BalloonHost::GetSource() const {
   return balloon_->notification().display_source();
@@ -133,10 +126,16 @@
 }
 
 bool BalloonHost::OnMessageReceived(const IPC::Message& message) {
-  if (extension_function_dispatcher_.get())
-    return extension_function_dispatcher_->OnMessageReceived(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;
+}
 
-  return false;
+void BalloonHost::OnRequest(const ExtensionHostMsg_Request_Params& params) {
+  extension_function_dispatcher_.Dispatch(params, render_view_host_);
 }
 
 // RenderViewHostDelegate::View methods implemented to allow links to
@@ -196,24 +195,8 @@
   DCHECK(!render_view_host_) << "BalloonViewHost already initialized.";
   RenderViewHost* rvh = new RenderViewHost(
       site_instance_.get(), this, MSG_ROUTING_NONE, NULL);
-  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_) {
+  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 9a70e61..2a03506 100644
--- a/chrome/browser/notifications/balloon_host.h
+++ b/chrome/browser/notifications/balloon_host.h
@@ -44,7 +44,7 @@
   // ExtensionFunctionDispatcher::Delegate overrides.
   virtual Browser* GetBrowser();
   virtual gfx::NativeView GetNativeViewOfHost();
-  virtual TabContents* associated_tab_contents() const;
+  virtual TabContents* GetAssociatedTabContents() const;
 
   RenderViewHost* render_view_host() const { return render_view_host_; }
 
@@ -137,6 +137,9 @@
   // 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();
@@ -158,14 +161,12 @@
   // 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 99c69a5..d1e4a33 100644
--- a/chrome/browser/sidebar/sidebar_container.cc
+++ b/chrome/browser/sidebar/sidebar_container.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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,7 +16,6 @@
 #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"
 
@@ -32,17 +31,6 @@
   // 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 0aa8434..c1760b7 100644
--- a/chrome/browser/ui/webui/options/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/extension_settings_handler.cc
@@ -20,7 +20,6 @@
 #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"
@@ -407,15 +406,13 @@
       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::EXTENSION_FUNCTION_DISPATCHER_DESTROYED,
-      NotificationService::AllSources());
   registrar_.Add(this,
       NotificationType::NAV_ENTRY_COMMITTED,
       NotificationService::AllSources());
   registrar_.Add(this,
+      NotificationType::RENDER_VIEW_HOST_CREATED,
+      NotificationService::AllSources());
+  registrar_.Add(this,
       NotificationType::RENDER_VIEW_HOST_DELETED,
       NotificationService::AllSources());
   registrar_.Add(this,
@@ -724,9 +721,11 @@
     // 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 &
-    // 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.
+    // 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).
     //
     // 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.
@@ -742,8 +741,7 @@
     case NotificationType::EXTENSION_PROCESS_CREATED:
     case NotificationType::EXTENSION_UNLOADED:
     case NotificationType::EXTENSION_UPDATE_DISABLED:
-    case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED:
-    case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED:
+    case NotificationType::RENDER_VIEW_HOST_CREATED:
     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 f5f1ace..8f4687b 100644
--- a/chrome/browser/visitedlink/visitedlink_unittest.cc
+++ b/chrome/browser/visitedlink/visitedlink_unittest.cc
@@ -505,7 +505,7 @@
         Source<RenderProcessHost>(this), NotificationService::NoDetails());
   }
 
-  virtual bool Init(bool is_accessibility_enabled, bool is_extension_process) {
+  virtual bool Init(bool is_accessibility_enabled) {
     return true;
   }
 
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc
index a2bb8c0..13339c3 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -35,7 +35,8 @@
 using WebKit::WebSecurityPolicy;
 using WebKit::WebString;
 
-ExtensionDispatcher::ExtensionDispatcher() {
+ExtensionDispatcher::ExtensionDispatcher()
+    : is_webkit_initialized_(false) {
   std::string type_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
       switches::kProcessType);
   is_extension_process_ = type_str == switches::kExtensionProcess ||
@@ -88,6 +89,17 @@
   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() {
@@ -202,6 +214,11 @@
   if (!extension)
     return;
 
+  if (is_webkit_initialized_)
+    InitHostPermissions(extension);
+}
+
+void ExtensionDispatcher::InitHostPermissions(const Extension* extension) {
   if (extension->HasApiPermission(Extension::kManagementPermission)) {
     WebSecurityPolicy::addOriginAccessWhitelistEntry(
         extension->url(),
@@ -210,13 +227,7 @@
         false);
   }
 
-  SetHostPermissions(extension->url(),
-                     extension->host_permissions());
-}
-
-void ExtensionDispatcher::SetHostPermissions(
-    const GURL& extension_url,
-    const std::vector<URLPattern>& permissions) {
+  const URLPatternList& permissions = extension->host_permissions();
   for (size_t i = 0; i < permissions.size(); ++i) {
     const char* schemes[] = {
       chrome::kHttpScheme,
@@ -227,7 +238,7 @@
     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 c966d37..bce3c0fb 100644
--- a/chrome/renderer/extensions/extension_dispatcher.h
+++ b/chrome/renderer/extensions/extension_dispatcher.h
@@ -81,9 +81,8 @@
   // extension is for Chrome Extensions only.
   void RegisterExtension(v8::Extension* extension, bool restrict_to_extensions);
 
-  // Sets the host permissions for a particular extension.
-  void SetHostPermissions(const GURL& extension_url,
-                          const std::vector<URLPattern>& permissions);
+  // Sets up the host permissions for |extension|.
+  void InitHostPermissions(const Extension* extension);
 
   // True if this renderer is running extensions.
   bool is_extension_process_;
@@ -108,6 +107,9 @@
   // 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 84603af..901097e 100644
--- a/content/browser/content_browser_client.cc
+++ b/content/browser/content_browser_client.cc
@@ -14,11 +14,6 @@
     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 d2b0824..6395d9a 100644
--- a/content/browser/content_browser_client.h
+++ b/content/browser/content_browser_client.h
@@ -34,11 +34,6 @@
   // Notifies that a new RenderHostView has been created.
   virtual void RenderViewHostCreated(RenderViewHost* render_view_host);
 
-  // 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.
diff --git a/content/browser/renderer_host/browser_render_process_host.cc b/content/browser/renderer_host/browser_render_process_host.cc
index 00aa5c3..9245a06a 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 @@
             base::TimeDelta::FromSeconds(5),
             this, &BrowserRenderProcessHost::ClearTransportDIBCache)),
       accessibility_enabled_(false),
-      extension_process_(false) {
+      is_initialized_(false) {
   widget_helper_ = new RenderWidgetHelper();
 
   WebCacheManager::GetInstance()->Add(id());
@@ -239,8 +239,7 @@
   ClearTransportDIBCache();
 }
 
-bool BrowserRenderProcessHost::Init(
-    bool is_accessibility_enabled, bool is_extensions_process) {
+bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) {
   // 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())
@@ -248,10 +247,6 @@
 
   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
@@ -332,6 +327,7 @@
     fast_shutdown_started_ = false;
   }
 
+  is_initialized_ = true;
   return true;
 }
 
@@ -470,8 +466,8 @@
   // Extensions use a special pseudo-process type to make them distinguishable,
   // even though they're just renderers.
   command_line->AppendSwitchASCII(switches::kProcessType,
-      extension_process_ ? switches::kExtensionProcess :
-                           switches::kRendererProcess);
+      is_extension_process_ ? switches::kExtensionProcess :
+                              switches::kRendererProcess);
 
   if (logging::DialogsAreSuppressed())
     command_line->AppendSwitch(switches::kNoErrorDialogs);
@@ -762,8 +758,13 @@
 
 bool BrowserRenderProcessHost::Send(IPC::Message* msg) {
   if (!channel_.get()) {
-    delete msg;
-    return false;
+    if (!is_initialized_) {
+      queued_messages_.push(msg);
+      return true;
+    } else {
+      delete msg;
+      return false;
+    }
   }
 
   if (child_process_launcher_.get() && child_process_launcher_->IsStarting()) {
@@ -852,15 +853,15 @@
   if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
       status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
     UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
-                             extension_process_ ? 2 : 1);
+                             is_extension_process_ ? 2 : 1);
   }
 
   if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
     UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
-                             extension_process_ ? 2 : 1);
+                             is_extension_process_ ? 2 : 1);
   }
 
-  RendererClosedDetails details(status, exit_code, extension_process_);
+  RendererClosedDetails details(status, exit_code, is_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 ca21e1e..9a5874fc 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 @@
   ~BrowserRenderProcessHost();
 
   // RenderProcessHost implementation (public portion).
-  virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process);
+  virtual bool Init(bool is_accessibility_enabled);
   virtual int GetNextRoutingID();
   virtual void CancelResourceRequests(int render_widget_id);
   virtual void CrossSiteSwapOutACK(const ViewMsg_SwapOut_Params& params);
@@ -131,9 +131,9 @@
   // True if this prcoess should have accessibility enabled;
   bool accessibility_enabled_;
 
-  // True iff this process is being used as an extension process. Not valid
-  // when running in single-process mode.
-  bool extension_process_;
+  // 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_;
 
   // 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 b4c9a9c..1ad0d73 100644
--- a/content/browser/renderer_host/mock_render_process_host.cc
+++ b/content/browser/renderer_host/mock_render_process_host.cc
@@ -23,8 +23,7 @@
     factory_->Remove(this);
 }
 
-bool MockRenderProcessHost::Init(
-    bool is_accessibility_enabled, bool is_extensions_process) {
+bool MockRenderProcessHost::Init(bool is_accessibility_enabled) {
   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 8faabfb0..67c96be 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 @@
   int bad_msg_count() const { return bad_msg_count_; }
 
   // RenderProcessHost implementation (public portion).
-  virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process);
+  virtual bool Init(bool is_accessibility_enabled);
   virtual int GetNextRoutingID();
   virtual void CancelResourceRequests(int render_widget_id);
   virtual void CrossSiteSwapOutACK(const ViewMsg_SwapOut_Params& params);
diff --git a/content/browser/renderer_host/render_process_host.cc b/content/browser/renderer_host/render_process_host.cc
index 379ce99..5466004 100644
--- a/content/browser/renderer_host/render_process_host.cc
+++ b/content/browser/renderer_host/render_process_host.cc
@@ -94,6 +94,7 @@
     : 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 66c3200..c8dfe01 100644
--- a/content/browser/renderer_host/render_process_host.h
+++ b/content/browser/renderer_host/render_process_host.h
@@ -88,6 +88,9 @@
     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.
@@ -163,8 +166,7 @@
   // 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, bool is_extensions_process) = 0;
+  virtual bool Init(bool is_accessibility_enabled) = 0;
 
   // Gets the next available routing id.
   virtual int GetNextRoutingID() = 0;
@@ -282,6 +284,10 @@
   // 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 a51b567..1b5f88f 100644
--- a/content/browser/renderer_host/render_view_host.cc
+++ b/content/browser/renderer_host/render_view_host.cc
@@ -104,7 +104,6 @@
       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_) {
@@ -116,6 +115,11 @@
   DCHECK(delegate_);
 
   content::GetContentClient()->browser()->RenderViewHostCreated(this);
+
+  NotificationService::current()->Notify(
+      NotificationType::RENDER_VIEW_HOST_CREATED,
+      Source<RenderViewHost>(this),
+      NotificationService::NoDetails());
 }
 
 RenderViewHost::~RenderViewHost() {
@@ -141,7 +145,7 @@
   // 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(), is_extension_process_))
+  if (!process()->Init(renderer_accessible()))
     return false;
   DCHECK(process()->HasConnection());
   DCHECK(process()->profile());
@@ -154,10 +158,6 @@
   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 add44a4..abc2bf0 100644
--- a/content/browser/renderer_host/render_view_host.h
+++ b/content/browser/renderer_host/render_view_host.h
@@ -335,12 +335,6 @@
   // 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);
@@ -625,10 +619,6 @@
   // 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 bac5374..8a364a0 100644
--- a/content/browser/tab_contents/render_view_host_manager.cc
+++ b/content/browser/tab_contents/render_view_host_manager.cc
@@ -547,11 +547,6 @@
   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 850b887..c7e4d6a0 100644
--- a/content/common/notification_type.h
+++ b/content/common/notification_type.h
@@ -459,6 +459,10 @@
     // 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,
@@ -865,18 +869,6 @@
     // 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,