1diff --git chrome/browser/extensions/api/streams_private/streams_private_api.cc chrome/browser/extensions/api/streams_private/streams_private_api.cc 2index 5c903a13a14ed..c85964a7bab17 100644 3--- chrome/browser/extensions/api/streams_private/streams_private_api.cc 4+++ chrome/browser/extensions/api/streams_private/streams_private_api.cc 5@@ -6,6 +6,7 @@ 6 7 #include <utility> 8 9+#include "cef/libcef/features/runtime.h" 10 #include "chrome/browser/extensions/extension_tab_util.h" 11 #include "chrome/browser/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h" 12 #include "components/no_state_prefetch/browser/no_state_prefetch_contents.h" 13@@ -18,6 +19,10 @@ 14 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" 15 #include "extensions/common/manifest_handlers/mime_types_handler.h" 16 17+#if BUILDFLAG(ENABLE_CEF) 18+#include "cef/libcef/browser/extensions/alloy_extensions_util.h" 19+#endif 20+ 21 namespace extensions { 22 23 void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent( 24@@ -42,6 +47,7 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent( 25 if (!web_contents) 26 return; 27 28+ if (!cef::IsAlloyRuntimeEnabled()) { 29 // If the request was for NoStatePrefetch, abort the prefetcher and do not 30 // continue. This is because plugins cancel NoStatePrefetch, see 31 // http://crbug.com/343590. 32@@ -52,6 +58,7 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent( 33 no_state_prefetch_contents->Destroy(prerender::FINAL_STATUS_DOWNLOAD); 34 return; 35 } 36+ } 37 38 auto* browser_context = web_contents->GetBrowserContext(); 39 40@@ -78,9 +85,18 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent( 41 // forms of zooming won't work). 42 // TODO(1042323): Present a coherent representation of a tab id for portal 43 // contents. 44- int tab_id = web_contents->GetOuterWebContents() 45- ? SessionID::InvalidValue().id() 46- : ExtensionTabUtil::GetTabId(web_contents); 47+ int tab_id; 48+ if (web_contents->GetOuterWebContents()) { 49+ tab_id = SessionID::InvalidValue().id(); 50+ } else 51+#if BUILDFLAG(ENABLE_CEF) 52+ if (cef::IsAlloyRuntimeEnabled()) { 53+ tab_id = alloy::GetTabIdForWebContents(web_contents); 54+ } else 55+#endif // BUILDFLAG(ENABLE_CEF) 56+ { 57+ tab_id = ExtensionTabUtil::GetTabId(web_contents); 58+ } 59 60 std::unique_ptr<StreamContainer> stream_container( 61 new StreamContainer(tab_id, embedded, handler_url, extension_id, 62diff --git extensions/browser/extension_host.cc extensions/browser/extension_host.cc 63index 3e827fcf45ae4..e1790599da17b 100644 64--- extensions/browser/extension_host.cc 65+++ extensions/browser/extension_host.cc 66@@ -60,11 +60,12 @@ ExtensionHost::ExtensionHost(const Extension* extension, 67 DCHECK(host_type == mojom::ViewType::kExtensionBackgroundPage || 68 host_type == mojom::ViewType::kExtensionDialog || 69 host_type == mojom::ViewType::kExtensionPopup); 70- host_contents_ = WebContents::Create( 71+ host_contents_owned_ = WebContents::Create( 72 WebContents::CreateParams(browser_context_, site_instance)), 73- content::WebContentsObserver::Observe(host_contents_.get()); 74+ host_contents_ = host_contents_owned_.get(); 75+ content::WebContentsObserver::Observe(host_contents_); 76 host_contents_->SetDelegate(this); 77- SetViewType(host_contents_.get(), host_type); 78+ SetViewType(host_contents_, host_type); 79 main_frame_host_ = host_contents_->GetMainFrame(); 80 81 // Listen for when an extension is unloaded from the same profile, as it may 82@@ -79,6 +80,44 @@ ExtensionHost::ExtensionHost(const Extension* extension, 83 ExtensionHostRegistry::Get(browser_context_)->ExtensionHostCreated(this); 84 } 85 86+ExtensionHost::ExtensionHost(ExtensionHostDelegate* delegate, 87+ const Extension* extension, 88+ content::BrowserContext* browser_context, 89+ content::WebContents* host_contents, 90+ const GURL& url, 91+ mojom::ViewType host_type) 92+ : delegate_(delegate), 93+ extension_(extension), 94+ extension_id_(extension->id()), 95+ browser_context_(browser_context), 96+ host_contents_(host_contents), 97+ initial_url_(url), 98+ extension_host_type_(host_type) { 99+ DCHECK(delegate); 100+ DCHECK(browser_context); 101+ DCHECK(host_contents); 102+ 103+ // Not used for panels, see PanelHost. 104+ DCHECK(host_type == mojom::ViewType::kExtensionBackgroundPage || 105+ host_type == mojom::ViewType::kExtensionDialog || 106+ host_type == mojom::ViewType::kExtensionPopup); 107+ 108+ content::WebContentsObserver::Observe(host_contents_); 109+ SetViewType(host_contents_, host_type); 110+ 111+ main_frame_host_ = host_contents_->GetMainFrame(); 112+ 113+ // Listen for when an extension is unloaded from the same profile, as it may 114+ // be the same extension that this points to. 115+ ExtensionRegistry::Get(browser_context_)->AddObserver(this); 116+ 117+ // Set up web contents observers and pref observers. 118+ delegate_->OnExtensionHostCreated(host_contents_); 119+ 120+ ExtensionWebContentsObserver::GetForWebContents(host_contents_)-> 121+ dispatcher()->set_delegate(this); 122+} 123+ 124 ExtensionHost::~ExtensionHost() { 125 ExtensionRegistry::Get(browser_context_)->RemoveObserver(this); 126 127diff --git extensions/browser/extension_host.h extensions/browser/extension_host.h 128index f88183071e861..a05302a7a2f0b 100644 129--- extensions/browser/extension_host.h 130+++ extensions/browser/extension_host.h 131@@ -53,6 +53,12 @@ class ExtensionHost : public DeferredStartRenderHost, 132 content::SiteInstance* site_instance, 133 const GURL& url, 134 mojom::ViewType host_type); 135+ ExtensionHost(ExtensionHostDelegate* delegate, 136+ const Extension* extension, 137+ content::BrowserContext* browser_context, 138+ content::WebContents* host_contents, 139+ const GURL& url, 140+ mojom::ViewType host_type); 141 142 ExtensionHost(const ExtensionHost&) = delete; 143 ExtensionHost& operator=(const ExtensionHost&) = delete; 144@@ -63,7 +69,7 @@ class ExtensionHost : public DeferredStartRenderHost, 145 const Extension* extension() const { return extension_; } 146 147 const std::string& extension_id() const { return extension_id_; } 148- content::WebContents* host_contents() const { return host_contents_.get(); } 149+ content::WebContents* host_contents() const { return host_contents_; } 150 content::RenderFrameHost* main_frame_host() const { return main_frame_host_; } 151 content::RenderProcessHost* render_process_host() const; 152 bool has_loaded_once() const { return has_loaded_once_; } 153@@ -189,7 +195,8 @@ class ExtensionHost : public DeferredStartRenderHost, 154 raw_ptr<content::BrowserContext> browser_context_; 155 156 // The host for our HTML content. 157- std::unique_ptr<content::WebContents> host_contents_; 158+ std::unique_ptr<content::WebContents> host_contents_owned_; 159+ content::WebContents* host_contents_; 160 161 // A pointer to the current or speculative main frame in `host_contents_`. We 162 // can't access this frame through the `host_contents_` directly as it does 163diff --git extensions/browser/extensions_browser_client.h extensions/browser/extensions_browser_client.h 164index 1fa1e67dddcfd..7af2a0e231824 100644 165--- extensions/browser/extensions_browser_client.h 166+++ extensions/browser/extensions_browser_client.h 167@@ -27,6 +27,7 @@ 168 #include "ui/base/page_transition_types.h" 169 170 class ExtensionFunctionRegistry; 171+class GURL; 172 class PrefService; 173 174 namespace base { 175@@ -66,6 +67,7 @@ class ComponentExtensionResourceManager; 176 class Extension; 177 class ExtensionCache; 178 class ExtensionError; 179+class ExtensionHost; 180 class ExtensionHostDelegate; 181 class ExtensionSet; 182 class ExtensionSystem; 183@@ -207,6 +209,14 @@ class ExtensionsBrowserClient { 184 virtual std::unique_ptr<ExtensionHostDelegate> 185 CreateExtensionHostDelegate() = 0; 186 187+ // CEF creates a custom ExtensionHost for background pages. If the return 188+ // value is true and |host| is NULL then fail the background host creation. 189+ virtual bool CreateBackgroundExtensionHost( 190+ const Extension* extension, 191+ content::BrowserContext* browser_context, 192+ const GURL& url, 193+ ExtensionHost** host) { return false; } 194+ 195 // Returns true if the client version has updated since the last run. Called 196 // once each time the extensions system is loaded per browser_context. The 197 // implementation may wish to use the BrowserContext to record the current 198diff --git extensions/browser/process_manager.cc extensions/browser/process_manager.cc 199index 9c5c1404df84a..e09394bb97547 100644 200--- extensions/browser/process_manager.cc 201+++ extensions/browser/process_manager.cc 202@@ -391,9 +391,17 @@ bool ProcessManager::CreateBackgroundHost(const Extension* extension, 203 return true; // TODO(kalman): return false here? It might break things... 204 205 DVLOG(1) << "CreateBackgroundHost " << extension->id(); 206- ExtensionHost* host = 207+ ExtensionHost* host = nullptr; 208+ if (ExtensionsBrowserClient::Get()->CreateBackgroundExtensionHost( 209+ extension, browser_context_, url, &host) && !host) { 210+ // Explicitly fail if the client can't create the host. 211+ return false; 212+ } 213+ if (!host) { 214+ host = 215 new ExtensionHost(extension, GetSiteInstanceForURL(url).get(), url, 216 mojom::ViewType::kExtensionBackgroundPage); 217+ } 218 host->CreateRendererSoon(); 219 OnBackgroundHostCreated(host); 220 return true; 221