Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1520)

Unified Diff: content/browser/tab_contents/render_view_host_manager.cc

Issue 6319001: Support window.opener after a process swap. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge with trunk. Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/tab_contents/render_view_host_manager.cc
diff --git a/content/browser/tab_contents/render_view_host_manager.cc b/content/browser/tab_contents/render_view_host_manager.cc
index 442e91c88e24598f46c2a474f69cc7f7e4863fa3..8a364a0e4e33477f0054fcf7cc669ef65f9cb98d 100644
--- a/content/browser/tab_contents/render_view_host_manager.cc
+++ b/content/browser/tab_contents/render_view_host_manager.cc
@@ -49,6 +49,13 @@ RenderViewHostManager::~RenderViewHostManager() {
RenderViewHost* render_view_host = render_view_host_;
render_view_host_ = NULL;
render_view_host->Shutdown();
+
+ // Shut down any swapped out RenderViewHosts.
+ for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
+ iter != swapped_out_hosts_.end();
+ ++iter) {
+ iter->second->Shutdown();
+ }
}
void RenderViewHostManager::Init(Profile* profile,
@@ -152,21 +159,17 @@ bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
if (pending_render_view_host_->are_navigations_suspended())
pending_render_view_host_->SetNavigationsSuspended(false);
} else {
- // The request has been started and paused, while we're waiting for the
+ // The request has been started and paused while we're waiting for the
// unload handler to finish. We'll pretend that it did, by notifying the
// IO thread to let the response continue. The pending renderer will then
// be swapped in as part of the usual DidNavigate logic. (If the unload
// handler later finishes, this call will be ignored because the state in
// CrossSiteResourceHandler will already be cleaned up.)
- ViewMsg_ClosePage_Params params;
- params.closing_process_id =
- render_view_host_->process()->id();
- params.closing_route_id = render_view_host_->routing_id();
- params.for_cross_site_transition = true;
+ ViewMsg_SwapOut_Params params;
params.new_render_process_host_id =
pending_render_view_host_->process()->id();
params.new_request_id = pending_request_id;
- current_host()->process()->CrossSiteClosePageACK(params);
+ current_host()->process()->CrossSiteSwapOutACK(params);
}
return false;
}
@@ -187,6 +190,14 @@ void RenderViewHostManager::DidNavigateMainFrame(
if (render_view_host == pending_render_view_host_) {
// The pending cross-site navigation completed, so show the renderer.
+ // If it committed without sending network requests (e.g., data URLs),
+ // then we still need to swap out the old RVH first and run its unload
+ // handler. OK for that to happen in the background.
+ if (pending_render_view_host_->GetPendingRequestId() == -1) {
+ OnCrossSiteResponse(pending_render_view_host_->process()->id(),
+ pending_render_view_host_->routing_id());
+ }
+
CommitPending();
cross_navigation_pending_ = false;
} else if (render_view_host == render_view_host_) {
@@ -221,8 +232,23 @@ void RenderViewHostManager::RendererAbortedProvisionalLoad(
void RenderViewHostManager::RendererProcessClosing(
RenderProcessHost* render_process_host) {
- // TODO(creis): Don't schedule new navigations in RenderViewHosts of this
- // process. (Part of http://crbug.com/65953.)
+ // Remove any swapped out RVHs from this process, so that we don't try to
+ // swap them back in while the process is exiting. Start by finding them,
+ // since there could be more than one.
+ std::list<int> ids_to_remove;
+ for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
+ iter != swapped_out_hosts_.end();
+ ++iter) {
+ if (iter->second->process() == render_process_host)
+ ids_to_remove.push_back(iter->first);
+ }
+
+ // Now delete them.
+ while (!ids_to_remove.empty()) {
+ swapped_out_hosts_[ids_to_remove.back()]->Shutdown();
+ swapped_out_hosts_.erase(ids_to_remove.back());
+ ids_to_remove.pop_back();
+ }
}
void RenderViewHostManager::ShouldClosePage(bool for_cross_site_transition,
@@ -254,7 +280,7 @@ void RenderViewHostManager::ShouldClosePage(bool for_cross_site_transition,
if (proceed_to_fire_unload) {
// This is not a cross-site navigation, the tab is being closed.
- render_view_host_->ClosePage(false, -1, -1);
+ render_view_host_->ClosePage();
}
}
}
@@ -266,12 +292,12 @@ void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id,
return;
DCHECK(pending_render_view_host_);
- // Tell the old renderer to run its onunload handler. When it finishes, it
- // will send a ClosePage_ACK to the ResourceDispatcherHost with the given
- // IDs (of the pending RVH's request), allowing the pending RVH's response to
- // resume.
- render_view_host_->ClosePage(true,
- new_render_process_host_id, new_request_id);
+ // Tell the old renderer it is being swapped out. This will fire the unload
+ // handler (without firing the beforeunload handler a second time). When the
+ // unload handler finishes and the navigation completes, we will send a
+ // message to the ResourceDispatcherHost with the given pending request IDs,
+ // allowing the pending RVH's response to resume.
+ render_view_host_->SwapOut(new_render_process_host_id, new_request_id);
// ResourceDispatcherHost has told us to run the onunload handler, which
// means it is not a download or unsafe page, and we are going to perform the
@@ -482,6 +508,21 @@ bool RenderViewHostManager::CreatePendingRenderView(
// we're about to switch away, so that it sends an UpdateState message.
}
+ // Check if we've already created an RVH for this SiteInstance.
+ CHECK(instance);
+ RenderViewHostMap::iterator iter =
+ swapped_out_hosts_.find(instance->id());
+ if (iter != swapped_out_hosts_.end()) {
+ // Re-use the existing RenderViewHost, which has already been initialized.
+ // We'll remove it from the list of swapped out hosts if it commits.
+ pending_render_view_host_ = iter->second;
+
+ // Prevent the process from exiting while we're trying to use it.
+ pending_render_view_host_->process()->AddPendingView();
+
+ return true;
+ }
+
pending_render_view_host_ = RenderViewHostFactory::Create(
instance, render_view_delegate_, MSG_ROUTING_NONE, delegate_->
GetControllerForRenderManager().session_storage_namespace());
@@ -536,14 +577,8 @@ void RenderViewHostManager::CommitPending() {
bool focus_render_view = !will_focus_location_bar &&
render_view_host_->view() && render_view_host_->view()->HasFocus();
- // Hide the current view and prepare to destroy it.
- // TODO(creis): Get the old RenderViewHost to send us an UpdateState message
- // before we destroy it.
- if (render_view_host_->view())
- render_view_host_->view()->Hide();
- RenderViewHost* old_render_view_host = render_view_host_;
-
// Swap in the pending view and make it active.
+ RenderViewHost* old_render_view_host = render_view_host_;
render_view_host_ = pending_render_view_host_;
pending_render_view_host_ = NULL;
@@ -558,6 +593,12 @@ void RenderViewHostManager::CommitPending() {
else
delegate_->RenderViewGoneFromRenderManager(render_view_host_);
+ // Hide the old view now that the new one is visible.
+ if (old_render_view_host->view()) {
+ old_render_view_host->view()->Hide();
+ old_render_view_host->WasSwappedOut();
+ }
+
// Make sure the size is up to date. (Fix for bug 1079768.)
delegate_->UpdateRenderViewSizeForRenderManager();
@@ -574,7 +615,18 @@ void RenderViewHostManager::CommitPending() {
Source<NavigationController>(&delegate_->GetControllerForRenderManager()),
Details<RenderViewHostSwitchedDetails>(&details));
- old_render_view_host->Shutdown();
+ // If the pending view was on the swapped out list, we can remove it.
+ swapped_out_hosts_.erase(render_view_host_->site_instance()->id());
+
+ // If the old RVH is live, we are swapping it out and should keep track of it
+ // in case we navigate back to it.
+ if (old_render_view_host->IsRenderViewLive()) {
+ DCHECK(old_render_view_host->is_swapped_out());
+ swapped_out_hosts_[old_render_view_host->site_instance()->id()] =
+ old_render_view_host;
+ } else {
+ old_render_view_host->Shutdown();
+ }
// Let the task manager know that we've swapped RenderViewHosts, since it
// might need to update its process groupings.
@@ -684,12 +736,26 @@ RenderViewHost* RenderViewHostManager::UpdateRendererStateForNavigate(
void RenderViewHostManager::CancelPending() {
RenderViewHost* pending_render_view_host = pending_render_view_host_;
+ pending_render_view_host_ = NULL;
// We no longer need to prevent the process from exiting.
pending_render_view_host->process()->RemovePendingView();
- pending_render_view_host_ = NULL;
- pending_render_view_host->Shutdown();
+ // The pending RVH may already be on the swapped out list if we started to
+ // swap it back in and then canceled. If so, make sure it gets swapped out
+ // again. If it's not on the swapped out list (e.g., aborting a pending
+ // load), then it's safe to shut down.
+ if (IsSwappedOut(pending_render_view_host)) {
+ // Any currently suspended navigations are no longer needed.
+ pending_render_view_host->CancelSuspendedNavigations();
+
+ // We can pass -1,-1 because there is no pending response in the
+ // ResourceDispatcherHost to unpause.
+ pending_render_view_host->SwapOut(-1, -1);
+ } else {
+ // We won't be coming back, so shut this one down.
+ pending_render_view_host->Shutdown();
+ }
pending_web_ui_.reset();
}
@@ -706,17 +772,33 @@ void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) {
NOTREACHED();
pending_render_view_host_ = NULL;
}
+
+ // Make sure deleted RVHs are not kept in the swapped out list while we are
+ // still alive. (If render_view_host_ is null, we're already being deleted.)
+ if (!render_view_host_)
+ return;
+ // We can't look it up by SiteInstance ID, which may no longer be valid.
+ for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
+ iter != swapped_out_hosts_.end();
+ ++iter) {
+ if (iter->second == rvh) {
+ swapped_out_hosts_.erase(iter);
+ break;
+ }
+ }
}
void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) {
+ // TODO(creis): Abstract out the common code between this and CommitPending.
web_ui_.reset();
- // Hide the current view and prepare to destroy it.
- if (render_view_host_->view())
- render_view_host_->view()->Hide();
- RenderViewHost* old_render_view_host = render_view_host_;
+ // Make sure the current RVH is swapped out so that it filters out any
+ // disruptive messages from the renderer. We can pass -1,-1 because there is
+ // no pending response in the ResourceDispatcherHost to unpause.
+ render_view_host_->SwapOut(-1, -1);
// Swap in the new view and make it active.
+ RenderViewHost* old_render_view_host = render_view_host_;
render_view_host_ = rvh;
render_view_host_->set_delegate(render_view_delegate_);
// Remove old RenderWidgetHostView with mocked out methods so it can be
@@ -738,6 +820,12 @@ void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) {
render_view_host_->view()->Show();
}
+ // Hide the current view and prepare to swap it out.
+ if (old_render_view_host->view()) {
+ old_render_view_host->view()->Hide();
+ old_render_view_host->WasSwappedOut();
+ }
+
delegate_->UpdateRenderViewSizeForRenderManager();
RenderViewHostSwitchedDetails details;
@@ -748,10 +836,28 @@ void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) {
Source<NavigationController>(&delegate_->GetControllerForRenderManager()),
Details<RenderViewHostSwitchedDetails>(&details));
- // This will cause the old RenderViewHost to delete itself.
- old_render_view_host->Shutdown();
+ // If the given RVH was on the swapped out list, we can remove it.
+ swapped_out_hosts_.erase(render_view_host_->site_instance()->id());
+
+ // If the old RVH is live, we are swapping it out and should keep track of it
+ // in case we navigate back to it.
+ if (old_render_view_host->IsRenderViewLive()) {
+ DCHECK(old_render_view_host->is_swapped_out());
+ swapped_out_hosts_[old_render_view_host->site_instance()->id()] =
+ old_render_view_host;
+ } else {
+ old_render_view_host->Shutdown();
+ }
// Let the task manager know that we've swapped RenderViewHosts, since it
// might need to update its process groupings.
delegate_->NotifySwappedFromRenderManager();
}
+
+bool RenderViewHostManager::IsSwappedOut(RenderViewHost* rvh) {
+ if (!rvh->site_instance())
+ return false;
+
+ return swapped_out_hosts_.find(rvh->site_instance()->id()) !=
+ swapped_out_hosts_.end();
+}

Powered by Google App Engine
This is Rietveld 408576698