diff --git chrome/browser/extensions/api/streams_private/streams_private_api.cc chrome/browser/extensions/api/streams_private/streams_private_api.cc
index 3841b7adf65d..41ca32ea5e2f 100644
--- chrome/browser/extensions/api/streams_private/streams_private_api.cc
+++ chrome/browser/extensions/api/streams_private/streams_private_api.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "cef/libcef/features/features.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/prerender/prerender_contents.h"
 #include "content/public/browser/browser_thread.h"
@@ -40,6 +41,7 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent(
   if (!web_contents)
     return;
 
+#if !BUILDFLAG(ENABLE_CEF)
   // If the request was for a prerender, abort the prerender and do not
   // continue. This is because plugins cancel prerender, see
   // http://crbug.com/343590.
@@ -49,6 +51,7 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent(
     prerender_contents->Destroy(prerender::FINAL_STATUS_DOWNLOAD);
     return;
   }
+#endif  // !BUILDFLAG(ENABLE_CEF)
 
   auto* browser_context = web_contents->GetBrowserContext();
 
diff --git extensions/browser/extension_host.cc extensions/browser/extension_host.cc
index 524c0603c138..f10ecd683aae 100644
--- extensions/browser/extension_host.cc
+++ extensions/browser/extension_host.cc
@@ -66,11 +66,12 @@ ExtensionHost::ExtensionHost(const Extension* extension,
   DCHECK(host_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
          host_type == VIEW_TYPE_EXTENSION_DIALOG ||
          host_type == VIEW_TYPE_EXTENSION_POPUP);
-  host_contents_ = WebContents::Create(
-      WebContents::CreateParams(browser_context_, site_instance)),
-  content::WebContentsObserver::Observe(host_contents_.get());
+  host_contents_owned_ = WebContents::Create(
+      WebContents::CreateParams(browser_context_, site_instance));
+  host_contents_ = host_contents_owned_.get();
+  content::WebContentsObserver::Observe(host_contents_);
   host_contents_->SetDelegate(this);
-  SetViewType(host_contents_.get(), host_type);
+  SetViewType(host_contents_, host_type);
 
   render_view_host_ = host_contents_->GetRenderViewHost();
 
@@ -85,6 +86,48 @@ ExtensionHost::ExtensionHost(const Extension* extension,
       dispatcher()->set_delegate(this);
 }
 
+ExtensionHost::ExtensionHost(ExtensionHostDelegate* delegate,
+                             const Extension* extension,
+                             content::BrowserContext* browser_context,
+                             content::WebContents* host_contents,
+                             const GURL& url,
+                             ViewType host_type)
+    : delegate_(delegate),
+      extension_(extension),
+      extension_id_(extension->id()),
+      browser_context_(browser_context),
+      host_contents_(host_contents),
+      render_view_host_(nullptr),
+      is_render_view_creation_pending_(false),
+      has_loaded_once_(false),
+      document_element_available_(false),
+      initial_url_(url),
+      extension_host_type_(host_type) {
+  DCHECK(delegate);
+  DCHECK(browser_context);
+  DCHECK(host_contents);
+
+  // Not used for panels, see PanelHost.
+  DCHECK(host_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
+         host_type == VIEW_TYPE_EXTENSION_DIALOG ||
+         host_type == VIEW_TYPE_EXTENSION_POPUP);
+
+  content::WebContentsObserver::Observe(host_contents_);
+  SetViewType(host_contents_, host_type);
+
+  render_view_host_ = host_contents_->GetRenderViewHost();
+
+  // Listen for when an extension is unloaded from the same profile, as it may
+  // be the same extension that this points to.
+  ExtensionRegistry::Get(browser_context_)->AddObserver(this);
+
+  // Set up web contents observers and pref observers.
+  delegate_->OnExtensionHostCreated(host_contents_);
+
+  ExtensionWebContentsObserver::GetForWebContents(host_contents_)->
+      dispatcher()->set_delegate(this);
+}
+
 ExtensionHost::~ExtensionHost() {
   ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
 
diff --git extensions/browser/extension_host.h extensions/browser/extension_host.h
index 093fb25589a9..3e6247802c52 100644
--- extensions/browser/extension_host.h
+++ extensions/browser/extension_host.h
@@ -52,13 +52,19 @@ class ExtensionHost : public DeferredStartRenderHost,
   ExtensionHost(const Extension* extension,
                 content::SiteInstance* site_instance,
                 const GURL& url, ViewType host_type);
+  ExtensionHost(ExtensionHostDelegate* delegate,
+                const Extension* extension,
+                content::BrowserContext* browser_context,
+                content::WebContents* host_contents,
+                const GURL& url,
+                ViewType host_type);
   ~ExtensionHost() override;
 
   // This may be null if the extension has been or is being unloaded.
   const Extension* extension() const { return extension_; }
 
   const std::string& extension_id() const { return extension_id_; }
-  content::WebContents* host_contents() const { return host_contents_.get(); }
+  content::WebContents* host_contents() const { return host_contents_; }
   content::RenderViewHost* render_view_host() const;
   content::RenderProcessHost* render_process_host() const;
   bool has_loaded_once() const { return has_loaded_once_; }
@@ -176,7 +182,8 @@ class ExtensionHost : public DeferredStartRenderHost,
   content::BrowserContext* browser_context_;
 
   // The host for our HTML content.
-  std::unique_ptr<content::WebContents> host_contents_;
+  std::unique_ptr<content::WebContents> host_contents_owned_;
+  content::WebContents* host_contents_;
 
   // A weak pointer to the current or pending RenderViewHost. We don't access
   // this through the host_contents because we want to deal with the pending
diff --git extensions/browser/extensions_browser_client.h extensions/browser/extensions_browser_client.h
index e697984786c5..dc84cfd92669 100644
--- extensions/browser/extensions_browser_client.h
+++ extensions/browser/extensions_browser_client.h
@@ -56,6 +56,7 @@ class ComponentExtensionResourceManager;
 class Extension;
 class ExtensionCache;
 class ExtensionError;
+class ExtensionHost;
 class ExtensionHostDelegate;
 class ExtensionSet;
 class ExtensionSystem;
@@ -195,6 +196,14 @@ class ExtensionsBrowserClient {
   virtual std::unique_ptr<ExtensionHostDelegate>
   CreateExtensionHostDelegate() = 0;
 
+  // CEF creates a custom ExtensionHost for background pages. If the return
+  // value is true and |host| is NULL then fail the background host creation.
+  virtual bool CreateBackgroundExtensionHost(
+      const Extension* extension,
+      content::BrowserContext* browser_context,
+      const GURL& url,
+      ExtensionHost** host) { return false; }
+
   // Returns true if the client version has updated since the last run. Called
   // once each time the extensions system is loaded per browser_context. The
   // implementation may wish to use the BrowserContext to record the current
diff --git extensions/browser/process_manager.cc extensions/browser/process_manager.cc
index 3c02c62162f1..13c355db03e0 100644
--- extensions/browser/process_manager.cc
+++ extensions/browser/process_manager.cc
@@ -386,9 +386,16 @@ bool ProcessManager::CreateBackgroundHost(const Extension* extension,
     return true;  // TODO(kalman): return false here? It might break things...
 
   DVLOG(1) << "CreateBackgroundHost " << extension->id();
-  ExtensionHost* host =
-      new ExtensionHost(extension, GetSiteInstanceForURL(url).get(), url,
-                        VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
+  ExtensionHost* host = nullptr;
+  if (ExtensionsBrowserClient::Get()->CreateBackgroundExtensionHost(
+          extension, browser_context_, url, &host) && !host) {
+    // Explicitly fail if the client can't create the host.
+    return false;
+  }
+  if (!host) {
+    host = new ExtensionHost(extension, GetSiteInstanceForURL(url).get(), url,
+                             VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
+  }
   host->CreateRenderViewSoon();
   OnBackgroundHostCreated(host);
   return true;