Index: content/browser/frame_host/render_frame_host_manager.cc |
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc |
index 5738861afde58d76599a11046288aee3948dfed6..72a03cebd07ce1366226c80888e004d2d884181d 100644 |
--- a/content/browser/frame_host/render_frame_host_manager.cc |
+++ b/content/browser/frame_host/render_frame_host_manager.cc |
@@ -74,7 +74,8 @@ RenderFrameHostManager::RenderFrameHostManager( |
render_frame_host_(NULL), |
pending_render_frame_host_(NULL), |
interstitial_page_(NULL), |
- cross_process_frame_connector_(NULL) {} |
+ cross_process_frame_connector_(NULL), |
+ weak_factory_(this) {} |
RenderFrameHostManager::~RenderFrameHostManager() { |
if (pending_render_frame_host_) |
@@ -236,7 +237,7 @@ bool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() { |
// If the tab becomes unresponsive during {before}unload while doing a |
// cross-site navigation, proceed with the navigation. (This assumes that |
// the pending RenderFrameHost is still responsive.) |
- if (render_frame_host_->render_view_host()->is_waiting_for_unload_ack()) { |
+ if (render_frame_host_->render_view_host()->IsWaitingForUnloadACK()) { |
// The request has been started and paused while we're waiting for the |
// unload handler to finish. We'll pretend that it did. The pending |
// renderer will then be swapped in as part of the usual DidNavigate logic. |
@@ -539,6 +540,15 @@ void RenderFrameHostManager::SwapOutOldPage() { |
} |
} |
+void RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance( |
+ int32 site_instance_id, |
+ RenderFrameHostImpl* rfh) { |
+ base::hash_map<int32, linked_ptr<RenderFrameHostImpl> >::iterator iter = |
+ pending_delete_hosts_.find(site_instance_id); |
+ if (iter != pending_delete_hosts_.end() && iter->second.get() == rfh) |
+ pending_delete_hosts_.erase(site_instance_id); |
+} |
+ |
void RenderFrameHostManager::Observe( |
int type, |
const NotificationSource& source, |
@@ -560,8 +570,30 @@ bool RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance( |
FrameTreeNode* node) { |
RenderFrameHostMap::iterator iter = |
node->render_manager()->swapped_out_hosts_.find(site_instance_id); |
- if (iter != node->render_manager()->swapped_out_hosts_.end()) |
- delete iter->second; |
+ if (iter != node->render_manager()->swapped_out_hosts_.end()) { |
+ RenderFrameHostImpl* swapped_out_rfh = iter->second; |
+ // If the RVH is pending swap out, it needs to switch state to |
+ // pending shutdown. Otherwise it is deleted. |
+ if (swapped_out_rfh->render_view_host()->rvh_state() == |
+ RenderViewHostImpl::STATE_PENDING_SWAP_OUT) { |
+ swapped_out_rfh->SetPendingShutdown(base::Bind( |
+ &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance, |
+ node->render_manager()->weak_factory_.GetWeakPtr(), |
+ site_instance_id, |
+ swapped_out_rfh)); |
+ RFHPendingDeleteMap::iterator pending_delete_iter = |
+ node->render_manager()->pending_delete_hosts_.find(site_instance_id); |
+ if (pending_delete_iter == |
+ node->render_manager()->pending_delete_hosts_.end() || |
+ pending_delete_iter->second.get() != iter->second) { |
+ node->render_manager()->pending_delete_hosts_[site_instance_id] = |
+ linked_ptr<RenderFrameHostImpl>(swapped_out_rfh); |
+ } |
+ } else { |
+ delete swapped_out_rfh; |
+ } |
+ node->render_manager()->swapped_out_hosts_.erase(site_instance_id); |
+ } |
return true; |
} |
@@ -944,7 +976,7 @@ bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host, |
// process unless it's swapped out. |
RenderViewHostImpl* rvh_impl = |
static_cast<RenderViewHostImpl*>(render_view_host); |
- if (!rvh_impl->is_swapped_out()) { |
+ if (rvh_impl->rvh_state() != RenderViewHostImpl::STATE_SWAPPED_OUT) { |
CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( |
render_view_host->GetProcess()->GetID())); |
} |
@@ -1019,10 +1051,16 @@ void RenderFrameHostManager::CommitPending() { |
// If the old view is live and top-level, hide it now that the new one is |
// visible. |
+ int32 old_site_instance_id = |
+ old_render_frame_host->render_view_host()->GetSiteInstance()->GetId(); |
if (old_render_frame_host->render_view_host()->GetView()) { |
if (is_main_frame) { |
old_render_frame_host->render_view_host()->GetView()->Hide(); |
- old_render_frame_host->render_view_host()->WasSwappedOut(); |
+ old_render_frame_host->render_view_host()->WasSwappedOut(base::Bind( |
+ &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance, |
+ weak_factory_.GetWeakPtr(), |
+ old_site_instance_id, |
+ old_render_frame_host)); |
} else { |
// TODO(creis): We'll need to set this back to false if we navigate back. |
old_render_frame_host->set_swapped_out(true); |
@@ -1056,18 +1094,17 @@ void RenderFrameHostManager::CommitPending() { |
if (old_render_frame_host->render_view_host()->IsRenderViewLive()) { |
// If the old RFH is live, we are swapping it out and should keep track of |
- // it in case we navigate back to it. |
+ // it in case we navigate back to it, or it is waiting for the unload event |
+ // to execute in the background. |
// TODO(creis): Swap out the subframe in --site-per-process. |
if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) |
DCHECK(old_render_frame_host->is_swapped_out() || |
- old_render_frame_host->render_view_host()->is_swapped_out()); |
- |
+ !RenderViewHostImpl::IsRVHStateActive( |
+ old_render_frame_host->render_view_host()->rvh_state())); |
// Temp fix for http://crbug.com/90867 until we do a better cleanup to make |
// sure we don't get different rvh instances for the same site instance |
// in the same rvhmgr. |
// TODO(creis): Clean this up. |
- int32 old_site_instance_id = |
- old_render_frame_host->render_view_host()->GetSiteInstance()->GetId(); |
RenderFrameHostMap::iterator iter = |
swapped_out_hosts_.find(old_site_instance_id); |
if (iter != swapped_out_hosts_.end() && |
@@ -1075,7 +1112,23 @@ void RenderFrameHostManager::CommitPending() { |
// Delete the RFH that will be replaced in the map to avoid a leak. |
delete iter->second; |
} |
- swapped_out_hosts_[old_site_instance_id] = old_render_frame_host; |
+ // If the RenderViewHost backing the RenderFrameHost is pending shutdown, |
+ // the RenderFrameHost should be put in the map of RenderFrameHost pending |
+ // shutdown. Otherwise, it is stored in the map of swapped out |
+ // RenderFrameHosts. |
+ if (old_render_frame_host->render_view_host()->rvh_state() == |
+ RenderViewHostImpl::STATE_PENDING_SHUTDOWN) { |
+ swapped_out_hosts_.erase(old_site_instance_id); |
+ RFHPendingDeleteMap::iterator pending_delete_iter = |
+ pending_delete_hosts_.find(old_site_instance_id); |
+ if (pending_delete_iter == pending_delete_hosts_.end() || |
+ pending_delete_iter->second.get() != old_render_frame_host) { |
+ pending_delete_hosts_[old_site_instance_id] = |
+ linked_ptr<RenderFrameHostImpl>(old_render_frame_host); |
+ } |
+ } else { |
+ swapped_out_hosts_[old_site_instance_id] = old_render_frame_host; |
+ } |
// If there are no active views in this SiteInstance, it means that |
// this RFH was the last active one in the SiteInstance. Now that we |
@@ -1118,7 +1171,6 @@ void RenderFrameHostManager::ShutdownRenderFrameHostsInSiteInstance( |
tree->ForEach(base::Bind( |
&RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance, |
site_instance_id)); |
- // rvh is now deleted. |
} |
} |
} |