// This observer ensures that the GuestViewBase destroys itself when its
// embedder goes away.
-class GuestViewBase::EmbedderWebContentsObserver : public WebContentsObserver {
+class GuestViewBase::EmbedderLifetimeObserver : public WebContentsObserver {
public:
- explicit EmbedderWebContentsObserver(GuestViewBase* guest)
- : WebContentsObserver(guest->embedder_web_contents()),
+ EmbedderLifetimeObserver(GuestViewBase* guest,
+ content::WebContents* embedder_web_contents)
+ : WebContentsObserver(embedder_web_contents),
destroyed_(false),
- guest_(guest) {
- }
+ guest_(guest) {}
- virtual ~EmbedderWebContentsObserver() {
- }
+ ~EmbedderLifetimeObserver() override {}
// WebContentsObserver implementation.
- virtual void WebContentsDestroyed() OVERRIDE {
+ void WebContentsDestroyed() override {
+ // If the embedder is destroyed then destroy the guest.
Destroy();
}
- virtual void RenderViewHostChanged(
- content::RenderViewHost* old_host,
- content::RenderViewHost* new_host) OVERRIDE {
+ void AboutToNavigateRenderView(
+ content::RenderViewHost* render_view_host) override {
+ // If the embedder navigates then destroy the guest.
Destroy();
}
- virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE {
+ void RenderProcessGone(base::TerminationStatus status) override {
+ // If the embedder crashes, then destroy the guest.
Destroy();
}
void Destroy() {
if (destroyed_)
return;
+
destroyed_ = true;
+ guest_->EmbedderWillBeDestroyed();
guest_->embedder_web_contents_ = NULL;
- guest_->EmbedderDestroyed();
guest_->Destroy();
}
- DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
+ DISALLOW_COPY_AND_ASSIGN(EmbedderLifetimeObserver);
+};
+
+// This observer ensures that the GuestViewBase destroys itself when its
+// embedder goes away.
+class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver {
+ public:
+ OpenerLifetimeObserver(GuestViewBase* guest)
+ : WebContentsObserver(guest->GetOpener()->web_contents()),
+ guest_(guest) {}
+
+ ~OpenerLifetimeObserver() override {}
+
+ // WebContentsObserver implementation.
+ void WebContentsDestroyed() override {
+ if (guest_->attached())
+ return;
+
+ // If the opener is destroyed then destroy the guest.
+ guest_->Destroy();
+ }
+
+ private:
+ GuestViewBase* guest_;
+
+ DISALLOW_COPY_AND_ASSIGN(OpenerLifetimeObserver);
};
GuestViewBase::GuestViewBase(content::BrowserContext* browser_context,
view_instance_id_(guestview::kInstanceIDNone),
element_instance_id_(guestview::kInstanceIDNone),
initialized_(false),
+ is_being_destroyed_(false),
auto_size_enabled_(false),
weak_ptr_factory_(this) {
}
embedder_site_url,
create_params,
base::Bind(&GuestViewBase::CompleteInit,
- AsWeakPtr(),
+ weak_ptr_factory_.GetWeakPtr(),
embedder_extension_id,
- embedder_process_id,
+ embedder_web_contents,
callback));
}
void GuestViewBase::InitWithWebContents(
const std::string& embedder_extension_id,
- int embedder_render_process_id,
+ content::WebContents* embedder_web_contents,
content::WebContents* guest_web_contents) {
DCHECK(guest_web_contents);
+ DCHECK(embedder_web_contents);
+ int embedder_render_process_id =
+ embedder_web_contents->GetRenderProcessHost()->GetID();
content::RenderProcessHost* embedder_render_process_host =
content::RenderProcessHost::FromID(embedder_render_process_id);
embedder_extension_id_ = embedder_extension_id;
embedder_render_process_id_ = embedder_render_process_host->GetID();
- embedder_render_process_host->AddObserver(this);
+
+ // At this point, we have just created the guest WebContents, we need to add
+ // an observer to the embedder WebContents. This observer will be responsible
+ // for destroying the guest WebContents if the embedder goes away.
+ embedder_lifetime_observer_.reset(
+ new EmbedderLifetimeObserver(this, embedder_web_contents));
WebContentsObserver::Observe(guest_web_contents);
guest_web_contents->SetDelegate(this);
return !!GuestViewBase::FromWebContents(web_contents);
}
-base::WeakPtr<GuestViewBase> GuestViewBase::AsWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
-}
-
bool GuestViewBase::IsAutoSizeSupported() const {
return false;
}
return false;
}
-void GuestViewBase::RenderProcessExited(content::RenderProcessHost* host,
- base::ProcessHandle handle,
- base::TerminationStatus status,
- int exit_code) {
- // GuestViewBase tracks the lifetime of its embedder render process until it
- // is attached to a particular embedder WebContents. At that point, its
- // lifetime is restricted in scope to the lifetime of its embedder
- // WebContents.
- CHECK(!attached());
- CHECK_EQ(host->GetID(), embedder_render_process_id());
-
- // This code path may be reached if the embedder WebContents is killed for
- // whatever reason immediately after a called to GuestViewInternal.createGuest
- // and before attaching the new guest to a frame.
- Destroy();
-}
-
-void GuestViewBase::Destroy() {
- DCHECK(web_contents());
- content::RenderProcessHost* host =
- content::RenderProcessHost::FromID(embedder_render_process_id());
- if (host)
- host->RemoveObserver(this);
- WillDestroy();
- if (!destruction_callback_.is_null())
- destruction_callback_.Run();
-
- webcontents_guestview_map.Get().erase(web_contents());
- GuestViewManager::FromBrowserContext(browser_context_)->
- RemoveGuest(guest_instance_id_);
- pending_events_.clear();
-
- delete web_contents();
-}
-
void GuestViewBase::DidAttach(int guest_proxy_routing_id) {
+ opener_lifetime_observer_.reset();
+
// Give the derived class an opportunity to perform some actions.
DidAttachToEmbedder();
GuestSizeChangedDueToAutoSize(old_size, new_size);
}
+void GuestViewBase::Destroy() {
+ if (is_being_destroyed_)
+ return;
+
+ is_being_destroyed_ = true;
+
+ DCHECK(web_contents());
+
+ // Give the derived class an opportunity to perform some cleanup.
+ WillDestroy();
+
+ // Invalidate weak pointers now so that bound callbacks cannot be called late
+ // into destruction. We must call this after WillDestroy because derived types
+ // may wish to access their openers.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+
+ // Give the content module an opportunity to perform some cleanup.
+ if (!destruction_callback_.is_null())
+ destruction_callback_.Run();
+
+ webcontents_guestview_map.Get().erase(web_contents());
+ GuestViewManager::FromBrowserContext(browser_context_)->
+ RemoveGuest(guest_instance_id_);
+ pending_events_.clear();
+
+ delete web_contents();
+}
+
void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) {
attach_params_.reset(params.DeepCopy());
attach_params_->GetInteger(guestview::kParameterInstanceId,
void GuestViewBase::SetOpener(GuestViewBase* guest) {
if (guest && guest->IsViewType(GetViewType())) {
- opener_ = guest->AsWeakPtr();
+ opener_ = guest->weak_ptr_factory_.GetWeakPtr();
+ if (!attached())
+ opener_lifetime_observer_.reset(new OpenerLifetimeObserver(this));
return;
}
opener_ = base::WeakPtr<GuestViewBase>();
+ opener_lifetime_observer_.reset();
}
void GuestViewBase::RegisterDestructionCallback(
void GuestViewBase::WillAttach(content::WebContents* embedder_web_contents,
int element_instance_id) {
- // After attachment, this GuestViewBase's lifetime is restricted to the
- // lifetime of its embedder WebContents. Observing the RenderProcessHost
- // of the embedder is no longer necessary.
- embedder_web_contents->GetRenderProcessHost()->RemoveObserver(this);
embedder_web_contents_ = embedder_web_contents;
- embedder_web_contents_observer_.reset(
- new EmbedderWebContentsObserver(this));
+
+ // If we are attaching to a different WebContents than the one that created
+ // the guest, we need to create a new LifetimeObserver.
+ if (embedder_web_contents != embedder_lifetime_observer_->web_contents()) {
+ embedder_lifetime_observer_.reset(
+ new EmbedderLifetimeObserver(this, embedder_web_contents));
+ }
+
element_instance_id_ = element_instance_id;
WillAttachToEmbedder();
}
void GuestViewBase::WebContentsDestroyed() {
+ // Let the derived class know that its WebContents is in the process of
+ // being destroyed. web_contents() is still valid at this point.
+ // TODO(fsamuel): This allows for reentrant code into WebContents during
+ // destruction. This could potentially lead to bugs. Perhaps we should get rid
+ // of this?
GuestDestroyed();
+
+ // Self-destruct.
delete this;
}
}
void GuestViewBase::CompleteInit(const std::string& embedder_extension_id,
- int embedder_render_process_id,
+ content::WebContents* embedder_web_contents,
const WebContentsCreatedCallback& callback,
content::WebContents* guest_web_contents) {
if (!guest_web_contents) {
callback.Run(NULL);
return;
}
- InitWithWebContents(embedder_extension_id,
- embedder_render_process_id,
- guest_web_contents);
+ InitWithWebContents(
+ embedder_extension_id, embedder_web_contents, guest_web_contents);
callback.Run(guest_web_contents);
}