Home | History | Annotate | Download | only in frame_host
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/frame_host/render_frame_host_manager.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/command_line.h"
     10 #include "base/debug/trace_event.h"
     11 #include "base/logging.h"
     12 #include "content/browser/child_process_security_policy_impl.h"
     13 #include "content/browser/devtools/render_view_devtools_agent_host.h"
     14 #include "content/browser/frame_host/debug_urls.h"
     15 #include "content/browser/frame_host/interstitial_page_impl.h"
     16 #include "content/browser/frame_host/navigation_controller_impl.h"
     17 #include "content/browser/frame_host/navigation_entry_impl.h"
     18 #include "content/browser/renderer_host/render_process_host_impl.h"
     19 #include "content/browser/renderer_host/render_view_host_factory.h"
     20 #include "content/browser/renderer_host/render_view_host_impl.h"
     21 #include "content/browser/site_instance_impl.h"
     22 #include "content/browser/webui/web_ui_controller_factory_registry.h"
     23 #include "content/browser/webui/web_ui_impl.h"
     24 #include "content/common/view_messages.h"
     25 #include "content/port/browser/render_widget_host_view_port.h"
     26 #include "content/public/browser/content_browser_client.h"
     27 #include "content/public/browser/notification_service.h"
     28 #include "content/public/browser/notification_types.h"
     29 #include "content/public/browser/render_widget_host_iterator.h"
     30 #include "content/public/browser/user_metrics.h"
     31 #include "content/public/browser/web_ui_controller.h"
     32 #include "content/public/common/content_switches.h"
     33 #include "content/public/common/url_constants.h"
     34 
     35 namespace content {
     36 
     37 RenderFrameHostManager::PendingNavigationParams::PendingNavigationParams()
     38     : is_transfer(false), frame_id(-1), should_replace_current_entry(false) {
     39 }
     40 
     41 RenderFrameHostManager::PendingNavigationParams::PendingNavigationParams(
     42     const GlobalRequestID& global_request_id,
     43     bool is_transfer,
     44     const std::vector<GURL>& transfer_url_chain,
     45     Referrer referrer,
     46     PageTransition page_transition,
     47     int64 frame_id,
     48     bool should_replace_current_entry)
     49     : global_request_id(global_request_id),
     50       is_transfer(is_transfer),
     51       transfer_url_chain(transfer_url_chain),
     52       referrer(referrer),
     53       page_transition(page_transition),
     54       frame_id(frame_id),
     55       should_replace_current_entry(should_replace_current_entry) {
     56 }
     57 
     58 RenderFrameHostManager::PendingNavigationParams::~PendingNavigationParams() {}
     59 
     60 RenderFrameHostManager::RenderFrameHostManager(
     61     RenderFrameHostDelegate* render_frame_delegate,
     62     RenderViewHostDelegate* render_view_delegate,
     63     RenderWidgetHostDelegate* render_widget_delegate,
     64     Delegate* delegate)
     65     : delegate_(delegate),
     66       cross_navigation_pending_(false),
     67       render_frame_delegate_(render_frame_delegate),
     68       render_view_delegate_(render_view_delegate),
     69       render_widget_delegate_(render_widget_delegate),
     70       render_view_host_(NULL),
     71       pending_render_view_host_(NULL),
     72       interstitial_page_(NULL) {
     73 }
     74 
     75 RenderFrameHostManager::~RenderFrameHostManager() {
     76   if (pending_render_view_host_)
     77     CancelPending();
     78 
     79   // We should always have a main RenderViewHost except in some tests.
     80   RenderViewHostImpl* render_view_host = render_view_host_;
     81   render_view_host_ = NULL;
     82   if (render_view_host)
     83     render_view_host->Shutdown();
     84 
     85   // Shut down any swapped out RenderViewHosts.
     86   for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
     87        iter != swapped_out_hosts_.end();
     88        ++iter) {
     89     iter->second->Shutdown();
     90   }
     91 }
     92 
     93 void RenderFrameHostManager::Init(BrowserContext* browser_context,
     94                                   SiteInstance* site_instance,
     95                                   int routing_id,
     96                                   int main_frame_routing_id) {
     97   // Create a RenderViewHost, once we have an instance.  It is important to
     98   // immediately give this SiteInstance to a RenderViewHost so that it is
     99   // ref counted.
    100   if (!site_instance)
    101     site_instance = SiteInstance::Create(browser_context);
    102   render_view_host_ = static_cast<RenderViewHostImpl*>(
    103       RenderViewHostFactory::Create(
    104           site_instance, render_view_delegate_, render_frame_delegate_,
    105           render_widget_delegate_, routing_id, main_frame_routing_id, false,
    106           delegate_->IsHidden()));
    107   render_view_host_->AttachToFrameTree();
    108 
    109   // Keep track of renderer processes as they start to shut down or are
    110   // crashed/killed.
    111   registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
    112                  NotificationService::AllSources());
    113   registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSING,
    114                  NotificationService::AllSources());
    115 }
    116 
    117 RenderViewHostImpl* RenderFrameHostManager::current_host() const {
    118   return render_view_host_;
    119 }
    120 
    121 RenderViewHostImpl* RenderFrameHostManager::pending_render_view_host() const {
    122   return pending_render_view_host_;
    123 }
    124 
    125 RenderWidgetHostView* RenderFrameHostManager::GetRenderWidgetHostView() const {
    126   if (interstitial_page_)
    127     return interstitial_page_->GetView();
    128   if (!render_view_host_)
    129     return NULL;
    130   return render_view_host_->GetView();
    131 }
    132 
    133 void RenderFrameHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
    134   pending_web_ui_.reset(
    135       delegate_->CreateWebUIForRenderManager(entry.GetURL()));
    136   pending_and_current_web_ui_.reset();
    137 
    138   // If we have assigned (zero or more) bindings to this NavigationEntry in the
    139   // past, make sure we're not granting it different bindings than it had
    140   // before.  If so, note it and don't give it any bindings, to avoid a
    141   // potential privilege escalation.
    142   if (pending_web_ui_.get() &&
    143       entry.bindings() != NavigationEntryImpl::kInvalidBindings &&
    144       pending_web_ui_->GetBindings() != entry.bindings()) {
    145     RecordAction(UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
    146     pending_web_ui_.reset();
    147   }
    148 }
    149 
    150 RenderViewHostImpl* RenderFrameHostManager::Navigate(
    151     const NavigationEntryImpl& entry) {
    152   TRACE_EVENT0("browser", "RenderFrameHostManager:Navigate");
    153   // Create a pending RenderViewHost. It will give us the one we should use
    154   RenderViewHostImpl* dest_render_view_host =
    155       static_cast<RenderViewHostImpl*>(UpdateRendererStateForNavigate(entry));
    156   if (!dest_render_view_host)
    157     return NULL;  // We weren't able to create a pending render view host.
    158 
    159   // If the current render_view_host_ isn't live, we should create it so
    160   // that we don't show a sad tab while the dest_render_view_host fetches
    161   // its first page.  (Bug 1145340)
    162   if (dest_render_view_host != render_view_host_ &&
    163       !render_view_host_->IsRenderViewLive()) {
    164     // Note: we don't call InitRenderView here because we are navigating away
    165     // soon anyway, and we don't have the NavigationEntry for this host.
    166     delegate_->CreateRenderViewForRenderManager(render_view_host_,
    167                                                 MSG_ROUTING_NONE);
    168   }
    169 
    170   // If the renderer crashed, then try to create a new one to satisfy this
    171   // navigation request.
    172   if (!dest_render_view_host->IsRenderViewLive()) {
    173     // Recreate the opener chain.
    174     int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
    175         dest_render_view_host->GetSiteInstance());
    176     if (!InitRenderView(dest_render_view_host, opener_route_id))
    177       return NULL;
    178 
    179     // Now that we've created a new renderer, be sure to hide it if it isn't
    180     // our primary one.  Otherwise, we might crash if we try to call Show()
    181     // on it later.
    182     if (dest_render_view_host != render_view_host_ &&
    183         dest_render_view_host->GetView()) {
    184       dest_render_view_host->GetView()->Hide();
    185     } else {
    186       // This is our primary renderer, notify here as we won't be calling
    187       // CommitPending (which does the notify).
    188       delegate_->NotifySwappedFromRenderManager(NULL, render_view_host_);
    189     }
    190   }
    191 
    192   return dest_render_view_host;
    193 }
    194 
    195 void RenderFrameHostManager::Stop() {
    196   render_view_host_->Stop();
    197 
    198   // If we are cross-navigating, we should stop the pending renderers.  This
    199   // will lead to a DidFailProvisionalLoad, which will properly destroy them.
    200   if (cross_navigation_pending_) {
    201     pending_render_view_host_->Send(
    202         new ViewMsg_Stop(pending_render_view_host_->GetRoutingID()));
    203   }
    204 }
    205 
    206 void RenderFrameHostManager::SetIsLoading(bool is_loading) {
    207   render_view_host_->SetIsLoading(is_loading);
    208   if (pending_render_view_host_)
    209     pending_render_view_host_->SetIsLoading(is_loading);
    210 }
    211 
    212 bool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
    213   if (!cross_navigation_pending_)
    214     return true;
    215 
    216   // We should always have a pending RVH when there's a cross-process navigation
    217   // in progress.  Sanity check this for http://crbug.com/276333.
    218   CHECK(pending_render_view_host_);
    219 
    220   // If the tab becomes unresponsive during {before}unload while doing a
    221   // cross-site navigation, proceed with the navigation.  (This assumes that
    222   // the pending RenderViewHost is still responsive.)
    223   if (render_view_host_->is_waiting_for_unload_ack()) {
    224     // The request has been started and paused while we're waiting for the
    225     // unload handler to finish.  We'll pretend that it did.  The pending
    226     // renderer will then be swapped in as part of the usual DidNavigate logic.
    227     // (If the unload handler later finishes, this call will be ignored because
    228     // the pending_nav_params_ state will already be cleaned up.)
    229     current_host()->OnSwappedOut(true);
    230   } else if (render_view_host_->is_waiting_for_beforeunload_ack()) {
    231     // Haven't gotten around to starting the request, because we're still
    232     // waiting for the beforeunload handler to finish.  We'll pretend that it
    233     // did finish, to let the navigation proceed.  Note that there's a danger
    234     // that the beforeunload handler will later finish and possibly return
    235     // false (meaning the navigation should not proceed), but we'll ignore it
    236     // in this case because it took too long.
    237     if (pending_render_view_host_->are_navigations_suspended())
    238       pending_render_view_host_->SetNavigationsSuspended(
    239           false, base::TimeTicks::Now());
    240   }
    241   return false;
    242 }
    243 
    244 void RenderFrameHostManager::SwappedOut(RenderViewHost* render_view_host) {
    245   // Make sure this is from our current RVH, and that we have a pending
    246   // navigation from OnCrossSiteResponse.  (There may be no pending navigation
    247   // for data URLs that don't make network requests, for example.)   If not,
    248   // just return early and ignore.
    249   if (render_view_host != render_view_host_ || !pending_nav_params_.get()) {
    250     pending_nav_params_.reset();
    251     return;
    252   }
    253 
    254   // Now that the unload handler has run, we need to either initiate the
    255   // pending transfer (if there is one) or resume the paused response (if not).
    256   // TODO(creis): The blank swapped out page is visible during this time, but
    257   // we can shorten this by delivering the response directly, rather than
    258   // forcing an identical request to be made.
    259   if (pending_nav_params_->is_transfer) {
    260     // Treat the last URL in the chain as the destination and the remainder as
    261     // the redirect chain.
    262     CHECK(pending_nav_params_->transfer_url_chain.size());
    263     GURL transfer_url = pending_nav_params_->transfer_url_chain.back();
    264     pending_nav_params_->transfer_url_chain.pop_back();
    265 
    266     // We don't know whether the original request had |user_action| set to true.
    267     // However, since we force the navigation to be in the current tab, it
    268     // doesn't matter.
    269     render_view_host->GetDelegate()->RequestTransferURL(
    270         transfer_url,
    271         pending_nav_params_->transfer_url_chain,
    272         pending_nav_params_->referrer,
    273         pending_nav_params_->page_transition,
    274         CURRENT_TAB,
    275         pending_nav_params_->frame_id,
    276         pending_nav_params_->global_request_id,
    277         pending_nav_params_->should_replace_current_entry,
    278         true);
    279   } else if (pending_render_view_host_) {
    280     RenderProcessHostImpl* pending_process =
    281         static_cast<RenderProcessHostImpl*>(
    282             pending_render_view_host_->GetProcess());
    283     pending_process->ResumeDeferredNavigation(
    284         pending_nav_params_->global_request_id);
    285   }
    286   pending_nav_params_.reset();
    287 }
    288 
    289 void RenderFrameHostManager::DidNavigateMainFrame(
    290     RenderViewHost* render_view_host) {
    291   if (!cross_navigation_pending_) {
    292     DCHECK(!pending_render_view_host_);
    293 
    294     // We should only hear this from our current renderer.
    295     DCHECK(render_view_host == render_view_host_);
    296 
    297     // Even when there is no pending RVH, there may be a pending Web UI.
    298     if (pending_web_ui())
    299       CommitPending();
    300     return;
    301   }
    302 
    303   if (render_view_host == pending_render_view_host_) {
    304     // The pending cross-site navigation completed, so show the renderer.
    305     // If it committed without sending network requests (e.g., data URLs),
    306     // then we still need to swap out the old RVH first and run its unload
    307     // handler.  OK for that to happen in the background.
    308     if (pending_render_view_host_->HasPendingCrossSiteRequest())
    309       SwapOutOldPage();
    310 
    311     CommitPending();
    312     cross_navigation_pending_ = false;
    313   } else if (render_view_host == render_view_host_) {
    314     // A navigation in the original page has taken place.  Cancel the pending
    315     // one.
    316     CancelPending();
    317     cross_navigation_pending_ = false;
    318   } else {
    319     // No one else should be sending us DidNavigate in this state.
    320     DCHECK(false);
    321   }
    322 }
    323 
    324 void RenderFrameHostManager::DidDisownOpener(RenderViewHost* render_view_host) {
    325   // Notify all swapped out hosts, including the pending RVH.
    326   for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
    327        iter != swapped_out_hosts_.end();
    328        ++iter) {
    329     DCHECK_NE(iter->second->GetSiteInstance(),
    330               current_host()->GetSiteInstance());
    331     iter->second->DisownOpener();
    332   }
    333 }
    334 
    335 void RenderFrameHostManager::RendererAbortedProvisionalLoad(
    336     RenderViewHost* render_view_host) {
    337   // We used to cancel the pending renderer here for cross-site downloads.
    338   // However, it's not safe to do that because the download logic repeatedly
    339   // looks for this WebContents based on a render view ID.  Instead, we just
    340   // leave the pending renderer around until the next navigation event
    341   // (Navigate, DidNavigate, etc), which will clean it up properly.
    342   // TODO(creis): All of this will go away when we move the cross-site logic
    343   // to ResourceDispatcherHost, so that we intercept responses rather than
    344   // navigation events.  (That's necessary to support onunload anyway.)  Once
    345   // we've made that change, we won't create a pending renderer until we know
    346   // the response is not a download.
    347 }
    348 
    349 void RenderFrameHostManager::RendererProcessClosing(
    350     RenderProcessHost* render_process_host) {
    351   // Remove any swapped out RVHs from this process, so that we don't try to
    352   // swap them back in while the process is exiting.  Start by finding them,
    353   // since there could be more than one.
    354   std::list<int> ids_to_remove;
    355   for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
    356        iter != swapped_out_hosts_.end();
    357        ++iter) {
    358     if (iter->second->GetProcess() == render_process_host)
    359       ids_to_remove.push_back(iter->first);
    360   }
    361 
    362   // Now delete them.
    363   while (!ids_to_remove.empty()) {
    364     swapped_out_hosts_[ids_to_remove.back()]->Shutdown();
    365     swapped_out_hosts_.erase(ids_to_remove.back());
    366     ids_to_remove.pop_back();
    367   }
    368 }
    369 
    370 void RenderFrameHostManager::ShouldClosePage(
    371     bool for_cross_site_transition,
    372     bool proceed,
    373     const base::TimeTicks& proceed_time) {
    374   if (for_cross_site_transition) {
    375     // Ignore if we're not in a cross-site navigation.
    376     if (!cross_navigation_pending_)
    377       return;
    378 
    379     if (proceed) {
    380       // Ok to unload the current page, so proceed with the cross-site
    381       // navigation.  Note that if navigations are not currently suspended, it
    382       // might be because the renderer was deemed unresponsive and this call was
    383       // already made by ShouldCloseTabOnUnresponsiveRenderer.  In that case, it
    384       // is ok to do nothing here.
    385       if (pending_render_view_host_ &&
    386           pending_render_view_host_->are_navigations_suspended()) {
    387         pending_render_view_host_->SetNavigationsSuspended(false, proceed_time);
    388       }
    389     } else {
    390       // Current page says to cancel.
    391       CancelPending();
    392       cross_navigation_pending_ = false;
    393     }
    394   } else {
    395     // Non-cross site transition means closing the entire tab.
    396     bool proceed_to_fire_unload;
    397     delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
    398                                                   &proceed_to_fire_unload);
    399 
    400     if (proceed_to_fire_unload) {
    401       // If we're about to close the tab and there's a pending RVH, cancel it.
    402       // Otherwise, if the navigation in the pending RVH completes before the
    403       // close in the current RVH, we'll lose the tab close.
    404       if (pending_render_view_host_) {
    405         CancelPending();
    406         cross_navigation_pending_ = false;
    407       }
    408 
    409       // This is not a cross-site navigation, the tab is being closed.
    410       render_view_host_->ClosePage();
    411     }
    412   }
    413 }
    414 
    415 void RenderFrameHostManager::OnCrossSiteResponse(
    416     RenderViewHost* pending_render_view_host,
    417     const GlobalRequestID& global_request_id,
    418     bool is_transfer,
    419     const std::vector<GURL>& transfer_url_chain,
    420     const Referrer& referrer,
    421     PageTransition page_transition,
    422     int64 frame_id,
    423     bool should_replace_current_entry) {
    424   // This should be called either when the pending RVH is ready to commit or
    425   // when we realize that the current RVH's request requires a transfer.
    426   DCHECK(
    427       pending_render_view_host == pending_render_view_host_ ||
    428       pending_render_view_host == render_view_host_);
    429 
    430   // TODO(creis): Eventually we will want to check all navigation responses
    431   // here, but currently we pass information for a transfer if
    432   // ShouldSwapProcessesForRedirect returned true in the network stack.
    433   // In that case, we should set up a transfer after the unload handler runs.
    434   // If is_transfer is false, we will just run the unload handler and resume.
    435   pending_nav_params_.reset(new PendingNavigationParams(
    436       global_request_id, is_transfer, transfer_url_chain, referrer,
    437       page_transition, frame_id, should_replace_current_entry));
    438 
    439   // Run the unload handler of the current page.
    440   SwapOutOldPage();
    441 }
    442 
    443 void RenderFrameHostManager::SwapOutOldPage() {
    444   // Should only see this while we have a pending renderer or transfer.
    445   CHECK(cross_navigation_pending_ || pending_nav_params_.get());
    446 
    447   // Tell the renderer to suppress any further modal dialogs so that we can swap
    448   // it out.  This must be done before canceling any current dialog, in case
    449   // there is a loop creating additional dialogs.
    450   render_view_host_->SuppressDialogsUntilSwapOut();
    451 
    452   // Now close any modal dialogs that would prevent us from swapping out.  This
    453   // must be done separately from SwapOut, so that the PageGroupLoadDeferrer is
    454   // no longer on the stack when we send the SwapOut message.
    455   delegate_->CancelModalDialogsForRenderManager();
    456 
    457   // Tell the old renderer it is being swapped out.  This will fire the unload
    458   // handler (without firing the beforeunload handler a second time).  When the
    459   // unload handler finishes and the navigation completes, we will send a
    460   // message to the ResourceDispatcherHost, allowing the pending RVH's response
    461   // to resume.
    462   render_view_host_->SwapOut();
    463 
    464   // ResourceDispatcherHost has told us to run the onunload handler, which
    465   // means it is not a download or unsafe page, and we are going to perform the
    466   // navigation.  Thus, we no longer need to remember that the RenderViewHost
    467   // is part of a pending cross-site request.
    468   if (pending_render_view_host_)
    469     pending_render_view_host_->SetHasPendingCrossSiteRequest(false);
    470 }
    471 
    472 void RenderFrameHostManager::Observe(
    473     int type,
    474     const NotificationSource& source,
    475     const NotificationDetails& details) {
    476   switch (type) {
    477     case NOTIFICATION_RENDERER_PROCESS_CLOSED:
    478     case NOTIFICATION_RENDERER_PROCESS_CLOSING:
    479       RendererProcessClosing(
    480           Source<RenderProcessHost>(source).ptr());
    481       break;
    482 
    483     default:
    484       NOTREACHED();
    485   }
    486 }
    487 
    488 bool RenderFrameHostManager::ShouldTransitionCrossSite() {
    489   // False in the single-process mode, as it makes RVHs to accumulate
    490   // in swapped_out_hosts_.
    491   // True if we are using process-per-site-instance (default) or
    492   // process-per-site (kProcessPerSite).
    493   return
    494       !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
    495       !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab);
    496 }
    497 
    498 bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
    499     const NavigationEntry* current_entry,
    500     const NavigationEntryImpl* new_entry) const {
    501   DCHECK(new_entry);
    502 
    503   // If new_entry already has a SiteInstance, assume it is correct and use it.
    504   if (new_entry->site_instance())
    505     return false;
    506 
    507   // Check for reasons to swap processes even if we are in a process model that
    508   // doesn't usually swap (e.g., process-per-tab).  Any time we return true,
    509   // the new_entry will be rendered in a new SiteInstance AND BrowsingInstance.
    510 
    511   // We use the effective URL here, since that's what is used in the
    512   // SiteInstance's site and when we later call IsSameWebSite.  If there is no
    513   // current_entry, check the current SiteInstance's site, which might already
    514   // be committed to a Web UI URL (such as the NTP).
    515   BrowserContext* browser_context =
    516       delegate_->GetControllerForRenderManager().GetBrowserContext();
    517   const GURL& current_url = (current_entry) ?
    518       SiteInstanceImpl::GetEffectiveURL(browser_context,
    519                                         current_entry->GetURL()) :
    520       render_view_host_->GetSiteInstance()->GetSiteURL();
    521   const GURL& new_url = SiteInstanceImpl::GetEffectiveURL(browser_context,
    522                                                           new_entry->GetURL());
    523 
    524   // Don't force a new BrowsingInstance for debug URLs that are handled in the
    525   // renderer process, like javascript: or chrome://crash.
    526   if (IsRendererDebugURL(new_url))
    527     return false;
    528 
    529   // For security, we should transition between processes when one is a Web UI
    530   // page and one isn't.
    531   if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
    532           browser_context, current_url)) {
    533     // If so, force a swap if destination is not an acceptable URL for Web UI.
    534     // Here, data URLs are never allowed.
    535     if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
    536             browser_context, new_url, false)) {
    537       return true;
    538     }
    539   } else {
    540     // Force a swap if it's a Web UI URL.
    541     if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
    542             browser_context, new_url)) {
    543       return true;
    544     }
    545   }
    546 
    547   // Check with the content client as well.  Important to pass current_url here,
    548   // which uses the SiteInstance's site if there is no current_entry.
    549   if (GetContentClient()->browser()->ShouldSwapBrowsingInstancesForNavigation(
    550           render_view_host_->GetSiteInstance(), current_url, new_url)) {
    551     return true;
    552   }
    553 
    554   // We can't switch a RenderView between view source and non-view source mode
    555   // without screwing up the session history sometimes (when navigating between
    556   // "view-source:http://foo.com/" and "http://foo.com/", Blink doesn't treat
    557   // it as a new navigation). So require a BrowsingInstance switch.
    558   if (current_entry &&
    559       current_entry->IsViewSourceMode() != new_entry->IsViewSourceMode())
    560     return true;
    561 
    562   return false;
    563 }
    564 
    565 bool RenderFrameHostManager::ShouldReuseWebUI(
    566     const NavigationEntry* current_entry,
    567     const NavigationEntryImpl* new_entry) const {
    568   NavigationControllerImpl& controller =
    569       delegate_->GetControllerForRenderManager();
    570   return current_entry && web_ui_.get() &&
    571       (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
    572           controller.GetBrowserContext(), current_entry->GetURL()) ==
    573        WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
    574           controller.GetBrowserContext(), new_entry->GetURL()));
    575 }
    576 
    577 SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
    578     const NavigationEntryImpl& entry,
    579     SiteInstance* current_instance,
    580     bool force_browsing_instance_swap) {
    581   // Determine which SiteInstance to use for navigating to |entry|.
    582   const GURL& dest_url = entry.GetURL();
    583   NavigationControllerImpl& controller =
    584       delegate_->GetControllerForRenderManager();
    585   BrowserContext* browser_context = controller.GetBrowserContext();
    586 
    587   // If a swap is required, we need to force the SiteInstance AND
    588   // BrowsingInstance to be different ones, using CreateForURL.
    589   if (force_browsing_instance_swap) {
    590     // We shouldn't be forcing a swap if an entry already has a SiteInstance.
    591     CHECK(!entry.site_instance());
    592     return SiteInstance::CreateForURL(browser_context, dest_url);
    593   }
    594 
    595   // If the entry has an instance already we should use it.
    596   if (entry.site_instance())
    597     return entry.site_instance();
    598 
    599   // (UGLY) HEURISTIC, process-per-site only:
    600   //
    601   // If this navigation is generated, then it probably corresponds to a search
    602   // query.  Given that search results typically lead to users navigating to
    603   // other sites, we don't really want to use the search engine hostname to
    604   // determine the site instance for this navigation.
    605   //
    606   // NOTE: This can be removed once we have a way to transition between
    607   //       RenderViews in response to a link click.
    608   //
    609   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) &&
    610       PageTransitionCoreTypeIs(entry.GetTransitionType(),
    611                                PAGE_TRANSITION_GENERATED)) {
    612     return current_instance;
    613   }
    614 
    615   SiteInstanceImpl* current_site_instance =
    616       static_cast<SiteInstanceImpl*>(current_instance);
    617 
    618   // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it
    619   // for this entry.  We won't commit the SiteInstance to this site until the
    620   // navigation commits (in DidNavigate), unless the navigation entry was
    621   // restored or it's a Web UI as described below.
    622   if (!current_site_instance->HasSite()) {
    623     // If we've already created a SiteInstance for our destination, we don't
    624     // want to use this unused SiteInstance; use the existing one.  (We don't
    625     // do this check if the current_instance has a site, because for now, we
    626     // want to compare against the current URL and not the SiteInstance's site.
    627     // In this case, there is no current URL, so comparing against the site is
    628     // ok.  See additional comments below.)
    629     //
    630     // Also, if the URL should use process-per-site mode and there is an
    631     // existing process for the site, we should use it.  We can call
    632     // GetRelatedSiteInstance() for this, which will eagerly set the site and
    633     // thus use the correct process.
    634     bool use_process_per_site =
    635         RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
    636         RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
    637     if (current_site_instance->HasRelatedSiteInstance(dest_url) ||
    638         use_process_per_site) {
    639       return current_site_instance->GetRelatedSiteInstance(dest_url);
    640     }
    641 
    642     // For extensions, Web UI URLs (such as the new tab page), and apps we do
    643     // not want to use the current_instance if it has no site, since it will
    644     // have a RenderProcessHost of PRIV_NORMAL.  Create a new SiteInstance for
    645     // this URL instead (with the correct process type).
    646     if (current_site_instance->HasWrongProcessForURL(dest_url))
    647       return current_site_instance->GetRelatedSiteInstance(dest_url);
    648 
    649     // View-source URLs must use a new SiteInstance and BrowsingInstance.
    650     // TODO(nasko): This is the same condition as later in the function. This
    651     // should be taken into account when refactoring this method as part of
    652     // http://crbug.com/123007.
    653     if (entry.IsViewSourceMode())
    654       return SiteInstance::CreateForURL(browser_context, dest_url);
    655 
    656     // If we are navigating from a blank SiteInstance to a WebUI, make sure we
    657     // create a new SiteInstance.
    658     if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
    659             browser_context, dest_url)) {
    660         return SiteInstance::CreateForURL(browser_context, dest_url);
    661     }
    662 
    663     // Normally the "site" on the SiteInstance is set lazily when the load
    664     // actually commits. This is to support better process sharing in case
    665     // the site redirects to some other site: we want to use the destination
    666     // site in the site instance.
    667     //
    668     // In the case of session restore, as it loads all the pages immediately
    669     // we need to set the site first, otherwise after a restore none of the
    670     // pages would share renderers in process-per-site.
    671     if (entry.restore_type() != NavigationEntryImpl::RESTORE_NONE)
    672       current_site_instance->SetSite(dest_url);
    673 
    674     return current_site_instance;
    675   }
    676 
    677   // Otherwise, only create a new SiteInstance for a cross-site navigation.
    678 
    679   // TODO(creis): Once we intercept links and script-based navigations, we
    680   // will be able to enforce that all entries in a SiteInstance actually have
    681   // the same site, and it will be safe to compare the URL against the
    682   // SiteInstance's site, as follows:
    683   // const GURL& current_url = current_instance->site();
    684   // For now, though, we're in a hybrid model where you only switch
    685   // SiteInstances if you type in a cross-site URL.  This means we have to
    686   // compare the entry's URL to the last committed entry's URL.
    687   NavigationEntry* current_entry = controller.GetLastCommittedEntry();
    688   if (interstitial_page_) {
    689     // The interstitial is currently the last committed entry, but we want to
    690     // compare against the last non-interstitial entry.
    691     current_entry = controller.GetEntryAtOffset(-1);
    692   }
    693   // If there is no last non-interstitial entry (and current_instance already
    694   // has a site), then we must have been opened from another tab.  We want
    695   // to compare against the URL of the page that opened us, but we can't
    696   // get to it directly.  The best we can do is check against the site of
    697   // the SiteInstance.  This will be correct when we intercept links and
    698   // script-based navigations, but for now, it could place some pages in a
    699   // new process unnecessarily.  We should only hit this case if a page tries
    700   // to open a new tab to an interstitial-inducing URL, and then navigates
    701   // the page to a different same-site URL.  (This seems very unlikely in
    702   // practice.)
    703   const GURL& current_url = (current_entry) ? current_entry->GetURL() :
    704       current_instance->GetSiteURL();
    705 
    706   // View-source URLs must use a new SiteInstance and BrowsingInstance.
    707   // We don't need a swap when going from view-source to a debug URL like
    708   // chrome://crash, however.
    709   // TODO(creis): Refactor this method so this duplicated code isn't needed.
    710   // See http://crbug.com/123007.
    711   if (current_entry &&
    712       current_entry->IsViewSourceMode() != entry.IsViewSourceMode() &&
    713       !IsRendererDebugURL(dest_url)) {
    714     return SiteInstance::CreateForURL(browser_context, dest_url);
    715   }
    716 
    717   // Use the current SiteInstance for same site navigations, as long as the
    718   // process type is correct.  (The URL may have been installed as an app since
    719   // the last time we visited it.)
    720   if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
    721       !current_site_instance->HasWrongProcessForURL(dest_url)) {
    722     return current_instance;
    723   }
    724 
    725   // Start the new renderer in a new SiteInstance, but in the current
    726   // BrowsingInstance.  It is important to immediately give this new
    727   // SiteInstance to a RenderViewHost (if it is different than our current
    728   // SiteInstance), so that it is ref counted.  This will happen in
    729   // CreateRenderView.
    730   return current_instance->GetRelatedSiteInstance(dest_url);
    731 }
    732 
    733 int RenderFrameHostManager::CreateRenderView(
    734     SiteInstance* instance,
    735     int opener_route_id,
    736     bool swapped_out,
    737     bool hidden) {
    738   CHECK(instance);
    739   DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
    740 
    741   // We are creating a pending or swapped out RVH here.  We should never create
    742   // it in the same SiteInstance as our current RVH.
    743   CHECK_NE(render_view_host_->GetSiteInstance(), instance);
    744 
    745   // Check if we've already created an RVH for this SiteInstance.  If so, try
    746   // to re-use the existing one, which has already been initialized.  We'll
    747   // remove it from the list of swapped out hosts if it commits.
    748   RenderViewHostImpl* new_render_view_host = static_cast<RenderViewHostImpl*>(
    749       GetSwappedOutRenderViewHost(instance));
    750   if (new_render_view_host) {
    751     // Prevent the process from exiting while we're trying to use it.
    752     if (!swapped_out)
    753       new_render_view_host->GetProcess()->AddPendingView();
    754   } else {
    755     // Create a new RenderViewHost if we don't find an existing one.
    756     new_render_view_host = static_cast<RenderViewHostImpl*>(
    757         RenderViewHostFactory::Create(instance,
    758                                       render_view_delegate_,
    759                                       render_frame_delegate_,
    760                                       render_widget_delegate_,
    761                                       MSG_ROUTING_NONE,
    762                                       MSG_ROUTING_NONE,
    763                                       swapped_out,
    764                                       hidden));
    765 
    766     // If the new RVH is swapped out already, store it.  Otherwise prevent the
    767     // process from exiting while we're trying to navigate in it.
    768     if (swapped_out) {
    769       swapped_out_hosts_[instance->GetId()] = new_render_view_host;
    770     } else {
    771       new_render_view_host->GetProcess()->AddPendingView();
    772     }
    773 
    774     bool success = InitRenderView(new_render_view_host, opener_route_id);
    775     if (success) {
    776       // Don't show the view until we get a DidNavigate from it.
    777       new_render_view_host->GetView()->Hide();
    778     } else if (!swapped_out) {
    779       CancelPending();
    780     }
    781   }
    782 
    783   // Use this as our new pending RVH if it isn't swapped out.
    784   if (!swapped_out)
    785     pending_render_view_host_ = new_render_view_host;
    786 
    787   return new_render_view_host->GetRoutingID();
    788 }
    789 
    790 bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host,
    791                                             int opener_route_id) {
    792   // If the pending navigation is to a WebUI and the RenderView is not in a
    793   // guest process, tell the RenderView about any bindings it will need enabled.
    794   if (pending_web_ui() && !render_view_host->GetProcess()->IsGuest()) {
    795     render_view_host->AllowBindings(pending_web_ui()->GetBindings());
    796   } else {
    797     // Ensure that we don't create an unprivileged RenderView in a WebUI-enabled
    798     // process unless it's swapped out.
    799     RenderViewHostImpl* rvh_impl =
    800         static_cast<RenderViewHostImpl*>(render_view_host);
    801     if (!rvh_impl->is_swapped_out()) {
    802       CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
    803                 render_view_host->GetProcess()->GetID()));
    804     }
    805   }
    806 
    807   return delegate_->CreateRenderViewForRenderManager(render_view_host,
    808                                                      opener_route_id);
    809 }
    810 
    811 void RenderFrameHostManager::CommitPending() {
    812   // First check whether we're going to want to focus the location bar after
    813   // this commit.  We do this now because the navigation hasn't formally
    814   // committed yet, so if we've already cleared |pending_web_ui_| the call chain
    815   // this triggers won't be able to figure out what's going on.
    816   bool will_focus_location_bar = delegate_->FocusLocationBarByDefault();
    817 
    818   // We expect SwapOutOldPage to have canceled any modal dialogs and told the
    819   // renderer to suppress any further dialogs until it is swapped out.  However,
    820   // crash reports indicate that it's still possible for modal dialogs to exist
    821   // at this point, which poses a risk if we delete their RenderViewHost below.
    822   // Cancel them again to be safe.  http://crbug.com/324320.
    823   delegate_->CancelModalDialogsForRenderManager();
    824 
    825   // Next commit the Web UI, if any. Either replace |web_ui_| with
    826   // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or
    827   // leave |web_ui_| as is if reusing it.
    828   DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get()));
    829   if (pending_web_ui_) {
    830     web_ui_.reset(pending_web_ui_.release());
    831   } else if (!pending_and_current_web_ui_.get()) {
    832     web_ui_.reset();
    833   } else {
    834     DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get());
    835     pending_and_current_web_ui_.reset();
    836   }
    837 
    838   // It's possible for the pending_render_view_host_ to be NULL when we aren't
    839   // crossing process boundaries. If so, we just needed to handle the Web UI
    840   // committing above and we're done.
    841   if (!pending_render_view_host_) {
    842     if (will_focus_location_bar)
    843       delegate_->SetFocusToLocationBar(false);
    844     return;
    845   }
    846 
    847   // Remember if the page was focused so we can focus the new renderer in
    848   // that case.
    849   bool focus_render_view = !will_focus_location_bar &&
    850       render_view_host_->GetView() && render_view_host_->GetView()->HasFocus();
    851 
    852   // Swap in the pending view and make it active. Also ensure the FrameTree
    853   // stays in sync.
    854   RenderViewHostImpl* old_render_view_host = render_view_host_;
    855   render_view_host_ = pending_render_view_host_;
    856   pending_render_view_host_ = NULL;
    857   render_view_host_->AttachToFrameTree();
    858 
    859   // The process will no longer try to exit, so we can decrement the count.
    860   render_view_host_->GetProcess()->RemovePendingView();
    861 
    862   // If the view is gone, then this RenderViewHost died while it was hidden.
    863   // We ignored the RenderProcessGone call at the time, so we should send it now
    864   // to make sure the sad tab shows up, etc.
    865   if (!render_view_host_->GetView())
    866     delegate_->RenderProcessGoneFromRenderManager(render_view_host_);
    867   else if (!delegate_->IsHidden())
    868     render_view_host_->GetView()->Show();
    869 
    870   // Hide the old view now that the new one is visible.
    871   if (old_render_view_host->GetView()) {
    872     old_render_view_host->GetView()->Hide();
    873     old_render_view_host->WasSwappedOut();
    874   }
    875 
    876   // Make sure the size is up to date.  (Fix for bug 1079768.)
    877   delegate_->UpdateRenderViewSizeForRenderManager();
    878 
    879   if (will_focus_location_bar)
    880     delegate_->SetFocusToLocationBar(false);
    881   else if (focus_render_view && render_view_host_->GetView())
    882     RenderWidgetHostViewPort::FromRWHV(render_view_host_->GetView())->Focus();
    883 
    884   // Notify that we've swapped RenderViewHosts. We do this
    885   // before shutting down the RVH so that we can clean up
    886   // RendererResources related to the RVH first.
    887   delegate_->NotifySwappedFromRenderManager(old_render_view_host,
    888                                             render_view_host_);
    889 
    890   // If the pending view was on the swapped out list, we can remove it.
    891   swapped_out_hosts_.erase(render_view_host_->GetSiteInstance()->GetId());
    892 
    893   // If there are no active RVHs in this SiteInstance, it means that
    894   // this RVH was the last active one in the SiteInstance. Now that we
    895   // know that all RVHs are swapped out, we can delete all the RVHs in
    896   // this SiteInstance.
    897   if (!static_cast<SiteInstanceImpl*>(old_render_view_host->GetSiteInstance())->
    898           active_view_count()) {
    899     ShutdownRenderViewHostsInSiteInstance(
    900         old_render_view_host->GetSiteInstance()->GetId());
    901     // This is deleted while cleaning up the SitaInstance's views.
    902     old_render_view_host = NULL;
    903   } else if (old_render_view_host->IsRenderViewLive()) {
    904     // If the old RVH is live, we are swapping it out and should keep track of
    905     // it in case we navigate back to it.
    906     DCHECK(old_render_view_host->is_swapped_out());
    907     // Temp fix for http://crbug.com/90867 until we do a better cleanup to make
    908     // sure we don't get different rvh instances for the same site instance
    909     // in the same rvhmgr.
    910     // TODO(creis): Clean this up.
    911     int32 old_site_instance_id =
    912         old_render_view_host->GetSiteInstance()->GetId();
    913     RenderViewHostMap::iterator iter =
    914         swapped_out_hosts_.find(old_site_instance_id);
    915     if (iter != swapped_out_hosts_.end() &&
    916         iter->second != old_render_view_host) {
    917       // Shutdown the RVH that will be replaced in the map to avoid a leak.
    918       iter->second->Shutdown();
    919     }
    920     swapped_out_hosts_[old_site_instance_id] = old_render_view_host;
    921   } else {
    922     old_render_view_host->Shutdown();
    923     old_render_view_host = NULL;  // Shutdown() deletes it.
    924   }
    925 }
    926 
    927 void RenderFrameHostManager::ShutdownRenderViewHostsInSiteInstance(
    928     int32 site_instance_id) {
    929   // First remove any swapped out RVH for this SiteInstance from our
    930   // list.
    931   swapped_out_hosts_.erase(site_instance_id);
    932 
    933   scoped_ptr<RenderWidgetHostIterator> widgets(
    934       RenderWidgetHostImpl::GetAllRenderWidgetHosts());
    935   while (RenderWidgetHost* widget = widgets->GetNextHost()) {
    936     if (!widget->IsRenderView())
    937       continue;
    938     RenderViewHostImpl* rvh =
    939         static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget));
    940     if (site_instance_id == rvh->GetSiteInstance()->GetId())
    941       rvh->Shutdown();
    942   }
    943 }
    944 
    945 RenderViewHostImpl* RenderFrameHostManager::UpdateRendererStateForNavigate(
    946     const NavigationEntryImpl& entry) {
    947   // If we are currently navigating cross-process, we want to get back to normal
    948   // and then navigate as usual.
    949   if (cross_navigation_pending_) {
    950     if (pending_render_view_host_)
    951       CancelPending();
    952     cross_navigation_pending_ = false;
    953   }
    954 
    955   // render_view_host_'s SiteInstance and new_instance will not be deleted
    956   // before the end of this method, so we don't have to worry about their ref
    957   // counts dropping to zero.
    958   SiteInstance* current_instance = render_view_host_->GetSiteInstance();
    959   SiteInstance* new_instance = current_instance;
    960 
    961   // We do not currently swap processes for navigations in webview tag guests.
    962   bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme);
    963 
    964   // Determine if we need a new BrowsingInstance for this entry.  If true, this
    965   // implies that it will get a new SiteInstance (and likely process), and that
    966   // other tabs in the current BrosingInstance will be unalbe to script it.
    967   // This is used for cases that require a process swap even in the
    968   // process-per-tab model, such as WebUI pages.
    969   const NavigationEntry* current_entry =
    970       delegate_->GetLastCommittedNavigationEntryForRenderManager();
    971   bool force_swap = !is_guest_scheme &&
    972       ShouldSwapBrowsingInstancesForNavigation(current_entry, &entry);
    973   if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
    974     new_instance = GetSiteInstanceForEntry(entry, current_instance, force_swap);
    975 
    976   // If force_swap is true, we must use a different SiteInstance.  If we didn't,
    977   // we would have two RenderViewHosts in the same SiteInstance and the same
    978   // tab, resulting in page_id conflicts for their NavigationEntries.
    979   if (force_swap)
    980     CHECK_NE(new_instance, current_instance);
    981 
    982   if (new_instance != current_instance) {
    983     // New SiteInstance: create a pending RVH to navigate.
    984     DCHECK(!cross_navigation_pending_);
    985 
    986     // This will possibly create (set to NULL) a Web UI object for the pending
    987     // page. We'll use this later to give the page special access. This must
    988     // happen before the new renderer is created below so it will get bindings.
    989     // It must also happen after the above conditional call to CancelPending(),
    990     // otherwise CancelPending may clear the pending_web_ui_ and the page will
    991     // not have its bindings set appropriately.
    992     SetPendingWebUI(entry);
    993 
    994     // Ensure that we have created RVHs for the new RVH's opener chain if
    995     // we are staying in the same BrowsingInstance. This allows the pending RVH
    996     // to send cross-process script calls to its opener(s).
    997     int opener_route_id = MSG_ROUTING_NONE;
    998     if (new_instance->IsRelatedSiteInstance(current_instance)) {
    999       opener_route_id =
   1000           delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
   1001     }
   1002 
   1003     // Create a non-swapped-out pending RVH with the given opener and navigate
   1004     // it.
   1005     int route_id = CreateRenderView(new_instance, opener_route_id, false,
   1006                                     delegate_->IsHidden());
   1007     if (route_id == MSG_ROUTING_NONE)
   1008       return NULL;
   1009 
   1010     // Check if our current RVH is live before we set up a transition.
   1011     if (!render_view_host_->IsRenderViewLive()) {
   1012       if (!cross_navigation_pending_) {
   1013         // The current RVH is not live.  There's no reason to sit around with a
   1014         // sad tab or a newly created RVH while we wait for the pending RVH to
   1015         // navigate.  Just switch to the pending RVH now and go back to non
   1016         // cross-navigating (Note that we don't care about on{before}unload
   1017         // handlers if the current RVH isn't live.)
   1018         CommitPending();
   1019         return render_view_host_;
   1020       } else {
   1021         NOTREACHED();
   1022         return render_view_host_;
   1023       }
   1024     }
   1025     // Otherwise, it's safe to treat this as a pending cross-site transition.
   1026 
   1027     // We need to wait until the beforeunload handler has run, unless we are
   1028     // transferring an existing request (in which case it has already run).
   1029     // Suspend the new render view (i.e., don't let it send the cross-site
   1030     // Navigate message) until we hear back from the old renderer's
   1031     // beforeunload handler.  If the handler returns false, we'll have to
   1032     // cancel the request.
   1033     DCHECK(!pending_render_view_host_->are_navigations_suspended());
   1034     bool is_transfer =
   1035         entry.transferred_global_request_id() != GlobalRequestID();
   1036     if (is_transfer) {
   1037       // We don't need to stop the old renderer or run beforeunload/unload
   1038       // handlers, because those have already been done.
   1039       DCHECK(pending_nav_params_->global_request_id ==
   1040                 entry.transferred_global_request_id());
   1041     } else {
   1042       // Also make sure the old render view stops, in case a load is in
   1043       // progress.  (We don't want to do this for transfers, since it will
   1044       // interrupt the transfer with an unexpected DidStopLoading.)
   1045       render_view_host_->Send(
   1046           new ViewMsg_Stop(render_view_host_->GetRoutingID()));
   1047 
   1048       pending_render_view_host_->SetNavigationsSuspended(true,
   1049                                                          base::TimeTicks());
   1050 
   1051       // Tell the CrossSiteRequestManager that this RVH has a pending cross-site
   1052       // request, so that ResourceDispatcherHost will know to tell us to run the
   1053       // old page's unload handler before it sends the response.
   1054       pending_render_view_host_->SetHasPendingCrossSiteRequest(true);
   1055     }
   1056 
   1057     // We now have a pending RVH.
   1058     DCHECK(!cross_navigation_pending_);
   1059     cross_navigation_pending_ = true;
   1060 
   1061     // Unless we are transferring an existing request, we should now
   1062     // tell the old render view to run its beforeunload handler, since it
   1063     // doesn't otherwise know that the cross-site request is happening.  This
   1064     // will trigger a call to ShouldClosePage with the reply.
   1065     if (!is_transfer)
   1066       render_view_host_->FirePageBeforeUnload(true);
   1067 
   1068     return pending_render_view_host_;
   1069   }
   1070 
   1071   // Otherwise the same SiteInstance can be used.  Navigate render_view_host_.
   1072   DCHECK(!cross_navigation_pending_);
   1073   if (ShouldReuseWebUI(current_entry, &entry)) {
   1074     pending_web_ui_.reset();
   1075     pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
   1076   } else {
   1077     SetPendingWebUI(entry);
   1078 
   1079     // Make sure the new RenderViewHost has the right bindings.
   1080     if (pending_web_ui() && !render_view_host_->GetProcess()->IsGuest())
   1081       render_view_host_->AllowBindings(pending_web_ui()->GetBindings());
   1082   }
   1083 
   1084   if (pending_web_ui() && render_view_host_->IsRenderViewLive())
   1085     pending_web_ui()->GetController()->RenderViewReused(render_view_host_);
   1086 
   1087   // The renderer can exit view source mode when any error or cancellation
   1088   // happen. We must overwrite to recover the mode.
   1089   if (entry.IsViewSourceMode()) {
   1090     render_view_host_->Send(
   1091         new ViewMsg_EnableViewSourceMode(render_view_host_->GetRoutingID()));
   1092   }
   1093 
   1094   return render_view_host_;
   1095 }
   1096 
   1097 void RenderFrameHostManager::CancelPending() {
   1098   RenderViewHostImpl* pending_render_view_host = pending_render_view_host_;
   1099   pending_render_view_host_ = NULL;
   1100 
   1101   RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
   1102       pending_render_view_host,
   1103       render_view_host_);
   1104 
   1105   // We no longer need to prevent the process from exiting.
   1106   pending_render_view_host->GetProcess()->RemovePendingView();
   1107 
   1108   // The pending RVH may already be on the swapped out list if we started to
   1109   // swap it back in and then canceled.  If so, make sure it gets swapped out
   1110   // again.  If it's not on the swapped out list (e.g., aborting a pending
   1111   // load), then it's safe to shut down.
   1112   if (IsOnSwappedOutList(pending_render_view_host)) {
   1113     // Any currently suspended navigations are no longer needed.
   1114     pending_render_view_host->CancelSuspendedNavigations();
   1115 
   1116     pending_render_view_host->SwapOut();
   1117   } else {
   1118     // We won't be coming back, so shut this one down.
   1119     pending_render_view_host->Shutdown();
   1120   }
   1121 
   1122   pending_web_ui_.reset();
   1123   pending_and_current_web_ui_.reset();
   1124 }
   1125 
   1126 void RenderFrameHostManager::RenderViewDeleted(RenderViewHost* rvh) {
   1127   // We are doing this in order to work around and to track a crasher
   1128   // (http://crbug.com/23411) where it seems that pending_render_view_host_ is
   1129   // deleted (not sure from where) but not NULLed.
   1130   if (rvh == pending_render_view_host_) {
   1131     // If you hit this NOTREACHED, please report it in the following bug
   1132     // http://crbug.com/23411 Make sure to include what you were doing when it
   1133     // happened  (navigating to a new page, closing a tab...) and if you can
   1134     // reproduce.
   1135     NOTREACHED();
   1136     pending_render_view_host_ = NULL;
   1137   }
   1138 
   1139   // Make sure deleted RVHs are not kept in the swapped out list while we are
   1140   // still alive.  (If render_view_host_ is null, we're already being deleted.)
   1141   if (!render_view_host_)
   1142     return;
   1143   // We can't look it up by SiteInstance ID, which may no longer be valid.
   1144   for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin();
   1145        iter != swapped_out_hosts_.end();
   1146        ++iter) {
   1147     if (iter->second == rvh) {
   1148       swapped_out_hosts_.erase(iter);
   1149       break;
   1150     }
   1151   }
   1152 }
   1153 
   1154 bool RenderFrameHostManager::IsOnSwappedOutList(RenderViewHost* rvh) const {
   1155   if (!rvh->GetSiteInstance())
   1156     return false;
   1157 
   1158   RenderViewHostMap::const_iterator iter = swapped_out_hosts_.find(
   1159       rvh->GetSiteInstance()->GetId());
   1160   if (iter == swapped_out_hosts_.end())
   1161     return false;
   1162 
   1163   return iter->second == rvh;
   1164 }
   1165 
   1166 RenderViewHostImpl* RenderFrameHostManager::GetSwappedOutRenderViewHost(
   1167     SiteInstance* instance) {
   1168   RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId());
   1169   if (iter != swapped_out_hosts_.end())
   1170     return iter->second;
   1171 
   1172   return NULL;
   1173 }
   1174 
   1175 }  // namespace content
   1176