Index: chrome/browser/extensions/api/messaging/extension_message_port.cc |
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.cc b/chrome/browser/extensions/api/messaging/extension_message_port.cc |
index aba30480fc5a704aa6b5e8512e73c5d42844f1c4..b517f9e66465835c08ecf6588b3f304fce2420a5 100644 |
--- a/chrome/browser/extensions/api/messaging/extension_message_port.cc |
+++ b/chrome/browser/extensions/api/messaging/extension_message_port.cc |
@@ -6,6 +6,7 @@ |
#include "base/scoped_observer.h" |
#include "chrome/browser/profiles/profile.h" |
+#include "content/public/browser/interstitial_page.h" |
#include "content/public/browser/navigation_details.h" |
#include "content/public/browser/render_frame_host.h" |
#include "content/public/browser/render_process_host.h" |
@@ -27,7 +28,7 @@ class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver, |
public ProcessManagerObserver { |
public: |
explicit FrameTracker(ExtensionMessagePort* port) |
- : pm_observer_(this), port_(port) {} |
+ : pm_observer_(this), port_(port), interstitial_frame_(nullptr) {} |
~FrameTracker() override {} |
void TrackExtensionProcessFrames() { |
@@ -38,6 +39,17 @@ class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver, |
Observe(tab); |
} |
+ void TrackInterstitialFrame(content::WebContents* tab, |
+ content::RenderFrameHost* interstitial_frame) { |
+ // |tab| should never be nullptr, because an interstitial's lifetime is |
+ // tied to a tab. This is a CHECK, not a DCHECK because we really need an |
+ // observer subject to detect frame removal (via DidDetachInterstitialPage). |
+ CHECK(tab); |
+ DCHECK(interstitial_frame); |
+ interstitial_frame_ = interstitial_frame; |
+ Observe(tab); |
+ } |
+ |
private: |
// content::WebContentsObserver overrides: |
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) |
@@ -45,12 +57,6 @@ class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver, |
port_->UnregisterFrame(render_frame_host); |
} |
- // TODO(robwu): This should be superfluous with RenderFrameDeleted above, but |
- // we are not entirely sure. |
- void FrameDeleted(content::RenderFrameHost* render_frame_host) override { |
- port_->UnregisterFrame(render_frame_host); |
- } |
- |
void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, |
const content::LoadCommittedDetails& details, |
const content::FrameNavigateParams&) override { |
@@ -58,6 +64,11 @@ class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver, |
port_->UnregisterFrame(render_frame_host); |
} |
+ void DidDetachInterstitialPage() override { |
+ if (interstitial_frame_) |
+ port_->UnregisterFrame(interstitial_frame_); |
+ } |
+ |
// extensions::ProcessManagerObserver overrides: |
void OnExtensionFrameUnregistered( |
const std::string& extension_id, |
@@ -69,6 +80,11 @@ class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver, |
ScopedObserver<ProcessManager, ProcessManagerObserver> pm_observer_; |
ExtensionMessagePort* port_; // Owns this FrameTracker. |
+ // Set to the main frame of an interstitial if we are tracking an interstitial |
+ // page, because RenderFrameDeleted is never triggered for frames in an |
+ // interstitial (and we only support tracking the interstitial's main frame). |
+ content::RenderFrameHost* interstitial_frame_; |
+ |
DISALLOW_COPY_AND_ASSIGN(FrameTracker); |
}; |
@@ -108,7 +124,28 @@ ExtensionMessagePort::ExtensionMessagePort( |
background_host_ptr_(nullptr), |
frame_tracker_(new FrameTracker(this)) { |
content::WebContents* tab = content::WebContents::FromRenderFrameHost(rfh); |
- CHECK(tab); |
+ if (!tab) { |
+ content::InterstitialPage* interstitial = |
+ content::InterstitialPage::FromRenderFrameHost(rfh); |
+ // A RenderFrameHost must be hosted in a WebContents or InterstitialPage. |
+ CHECK(interstitial); |
+ |
+ // Only the main frame of an interstitial is supported, because frames in |
+ // the interstitial do not trigger RenderFrameCreated / RenderFrameDeleted |
+ // on WebContentObservers. Consequently, (1) we cannot detect removal of |
+ // RenderFrameHosts, and (2) even if the RenderFrameDeleted is propagated, |
+ // then WebContentsObserverSanityChecker triggers a CHECK when it detects |
+ // frame notifications without a corresponding RenderFrameCreated. |
+ if (!rfh->GetParent()) { |
+ // It is safe to pass the interstitial's WebContents here because we only |
+ // use it to observe DidDetachInterstitialPage. |
+ frame_tracker_->TrackInterstitialFrame(interstitial->GetWebContents(), |
+ rfh); |
+ RegisterFrame(rfh); |
+ } |
+ return; |
+ } |
+ |
frame_tracker_->TrackTabFrames(tab); |
if (include_child_frames) { |
tab->ForEachFrame(base::Bind(&ExtensionMessagePort::RegisterFrame, |