| 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();
|
| +}
|
|
|