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 "base/stl_util.h"
     13 #include "content/browser/child_process_security_policy_impl.h"
     14 #include "content/browser/devtools/render_view_devtools_agent_host.h"
     15 #include "content/browser/frame_host/cross_site_transferring_request.h"
     16 #include "content/browser/frame_host/debug_urls.h"
     17 #include "content/browser/frame_host/interstitial_page_impl.h"
     18 #include "content/browser/frame_host/navigation_before_commit_info.h"
     19 #include "content/browser/frame_host/navigation_controller_impl.h"
     20 #include "content/browser/frame_host/navigation_entry_impl.h"
     21 #include "content/browser/frame_host/navigation_request.h"
     22 #include "content/browser/frame_host/navigation_request_info.h"
     23 #include "content/browser/frame_host/navigator.h"
     24 #include "content/browser/frame_host/render_frame_host_factory.h"
     25 #include "content/browser/frame_host/render_frame_host_impl.h"
     26 #include "content/browser/frame_host/render_frame_proxy_host.h"
     27 #include "content/browser/renderer_host/render_process_host_impl.h"
     28 #include "content/browser/renderer_host/render_view_host_factory.h"
     29 #include "content/browser/renderer_host/render_view_host_impl.h"
     30 #include "content/browser/site_instance_impl.h"
     31 #include "content/browser/webui/web_ui_controller_factory_registry.h"
     32 #include "content/browser/webui/web_ui_impl.h"
     33 #include "content/common/view_messages.h"
     34 #include "content/public/browser/content_browser_client.h"
     35 #include "content/public/browser/notification_service.h"
     36 #include "content/public/browser/notification_types.h"
     37 #include "content/public/browser/render_widget_host_iterator.h"
     38 #include "content/public/browser/render_widget_host_view.h"
     39 #include "content/public/browser/user_metrics.h"
     40 #include "content/public/browser/web_ui_controller.h"
     41 #include "content/public/common/content_switches.h"
     42 #include "content/public/common/referrer.h"
     43 #include "content/public/common/url_constants.h"
     44 #include "net/base/load_flags.h"
     45 
     46 namespace content {
     47 
     48 namespace {
     49 
     50 // PlzNavigate
     51 // Simulates a renderer response to a navigation request when there is no live
     52 // renderer.
     53 FrameHostMsg_BeginNavigation_Params BeginNavigationFromNavigate(
     54     const FrameMsg_Navigate_Params& navigate_params) {
     55   FrameHostMsg_BeginNavigation_Params begin_navigation_params;
     56   begin_navigation_params.method = navigate_params.is_post ? "POST" : "GET";
     57   begin_navigation_params.url = navigate_params.url;
     58   begin_navigation_params.referrer =
     59       Referrer(navigate_params.referrer.url, navigate_params.referrer.policy);
     60 
     61   // TODO(clamy): This should be modified to take into account caching policy
     62   // requirements (eg for POST reloads).
     63   begin_navigation_params.load_flags = net::LOAD_NORMAL;
     64 
     65   // TODO(clamy): Post data from the browser should be put in the request body.
     66 
     67   begin_navigation_params.has_user_gesture = false;
     68   begin_navigation_params.transition_type = navigate_params.transition;
     69   begin_navigation_params.should_replace_current_entry =
     70       navigate_params.should_replace_current_entry;
     71   begin_navigation_params.allow_download =
     72       navigate_params.allow_download;
     73   return begin_navigation_params;
     74 }
     75 
     76 }  // namespace
     77 
     78 bool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) {
     79   node->render_manager()->pending_delete_hosts_.clear();
     80   return true;
     81 }
     82 
     83 RenderFrameHostManager::RenderFrameHostManager(
     84     FrameTreeNode* frame_tree_node,
     85     RenderFrameHostDelegate* render_frame_delegate,
     86     RenderViewHostDelegate* render_view_delegate,
     87     RenderWidgetHostDelegate* render_widget_delegate,
     88     Delegate* delegate)
     89     : frame_tree_node_(frame_tree_node),
     90       delegate_(delegate),
     91       cross_navigation_pending_(false),
     92       render_frame_delegate_(render_frame_delegate),
     93       render_view_delegate_(render_view_delegate),
     94       render_widget_delegate_(render_widget_delegate),
     95       interstitial_page_(NULL),
     96       weak_factory_(this) {
     97   DCHECK(frame_tree_node_);
     98 }
     99 
    100 RenderFrameHostManager::~RenderFrameHostManager() {
    101   if (pending_render_frame_host_)
    102     CancelPending();
    103 
    104   // We should always have a current RenderFrameHost except in some tests.
    105   SetRenderFrameHost(scoped_ptr<RenderFrameHostImpl>());
    106 
    107   // Delete any swapped out RenderFrameHosts.
    108   STLDeleteValues(&proxy_hosts_);
    109 
    110   // PlzNavigate
    111   // There is an active navigation request for this RFHM so it needs to be
    112   // canceled.
    113   if (CommandLine::ForCurrentProcess()->HasSwitch(
    114       switches::kEnableBrowserSideNavigation)) {
    115     if (navigation_request_.get())
    116       navigation_request_->CancelNavigation();
    117   }
    118 
    119 }
    120 
    121 void RenderFrameHostManager::Init(BrowserContext* browser_context,
    122                                   SiteInstance* site_instance,
    123                                   int view_routing_id,
    124                                   int frame_routing_id) {
    125   // Create a RenderViewHost and RenderFrameHost, once we have an instance.  It
    126   // is important to immediately give this SiteInstance to a RenderViewHost so
    127   // that the SiteInstance is ref counted.
    128   if (!site_instance)
    129     site_instance = SiteInstance::Create(browser_context);
    130 
    131   SetRenderFrameHost(CreateRenderFrameHost(site_instance,
    132                                            view_routing_id,
    133                                            frame_routing_id,
    134                                            false,
    135                                            delegate_->IsHidden()));
    136 
    137   // Keep track of renderer processes as they start to shut down or are
    138   // crashed/killed.
    139   registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
    140                  NotificationService::AllSources());
    141   registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSING,
    142                  NotificationService::AllSources());
    143 }
    144 
    145 RenderViewHostImpl* RenderFrameHostManager::current_host() const {
    146   if (!render_frame_host_)
    147     return NULL;
    148   return render_frame_host_->render_view_host();
    149 }
    150 
    151 RenderViewHostImpl* RenderFrameHostManager::pending_render_view_host() const {
    152   if (!pending_render_frame_host_)
    153     return NULL;
    154   return pending_render_frame_host_->render_view_host();
    155 }
    156 
    157 RenderWidgetHostView* RenderFrameHostManager::GetRenderWidgetHostView() const {
    158   if (interstitial_page_)
    159     return interstitial_page_->GetView();
    160   if (!render_frame_host_)
    161     return NULL;
    162   return render_frame_host_->render_view_host()->GetView();
    163 }
    164 
    165 RenderFrameProxyHost* RenderFrameHostManager::GetProxyToParent() {
    166   if (frame_tree_node_->IsMainFrame())
    167     return NULL;
    168 
    169   RenderFrameProxyHostMap::iterator iter =
    170       proxy_hosts_.find(frame_tree_node_->parent()
    171                             ->render_manager()
    172                             ->current_frame_host()
    173                             ->GetSiteInstance()
    174                             ->GetId());
    175   if (iter == proxy_hosts_.end())
    176     return NULL;
    177 
    178   return iter->second;
    179 }
    180 
    181 void RenderFrameHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
    182   pending_web_ui_.reset(
    183       delegate_->CreateWebUIForRenderManager(entry.GetURL()));
    184   pending_and_current_web_ui_.reset();
    185 
    186   // If we have assigned (zero or more) bindings to this NavigationEntry in the
    187   // past, make sure we're not granting it different bindings than it had
    188   // before.  If so, note it and don't give it any bindings, to avoid a
    189   // potential privilege escalation.
    190   if (pending_web_ui_.get() &&
    191       entry.bindings() != NavigationEntryImpl::kInvalidBindings &&
    192       pending_web_ui_->GetBindings() != entry.bindings()) {
    193     RecordAction(
    194         base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
    195     pending_web_ui_.reset();
    196   }
    197 }
    198 
    199 RenderFrameHostImpl* RenderFrameHostManager::Navigate(
    200     const NavigationEntryImpl& entry) {
    201   TRACE_EVENT1("navigation", "RenderFrameHostManager:Navigate",
    202                "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
    203   // Create a pending RenderFrameHost to use for the navigation.
    204   RenderFrameHostImpl* dest_render_frame_host = UpdateStateForNavigate(entry);
    205   if (!dest_render_frame_host)
    206     return NULL;  // We weren't able to create a pending render frame host.
    207 
    208   // If the current render_frame_host_ isn't live, we should create it so
    209   // that we don't show a sad tab while the dest_render_frame_host fetches
    210   // its first page.  (Bug 1145340)
    211   if (dest_render_frame_host != render_frame_host_ &&
    212       !render_frame_host_->IsRenderFrameLive()) {
    213     // Note: we don't call InitRenderView here because we are navigating away
    214     // soon anyway, and we don't have the NavigationEntry for this host.
    215     delegate_->CreateRenderViewForRenderManager(
    216         render_frame_host_->render_view_host(), MSG_ROUTING_NONE,
    217         MSG_ROUTING_NONE, frame_tree_node_->IsMainFrame());
    218   }
    219 
    220   // If the renderer crashed, then try to create a new one to satisfy this
    221   // navigation request.
    222   if (!dest_render_frame_host->IsRenderFrameLive()) {
    223     // Recreate the opener chain.
    224     int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
    225         dest_render_frame_host->GetSiteInstance());
    226     if (!InitRenderView(dest_render_frame_host->render_view_host(),
    227                         opener_route_id,
    228                         MSG_ROUTING_NONE,
    229                         frame_tree_node_->IsMainFrame()))
    230       return NULL;
    231 
    232     // Now that we've created a new renderer, be sure to hide it if it isn't
    233     // our primary one.  Otherwise, we might crash if we try to call Show()
    234     // on it later.
    235     if (dest_render_frame_host != render_frame_host_ &&
    236         dest_render_frame_host->render_view_host()->GetView()) {
    237       dest_render_frame_host->render_view_host()->GetView()->Hide();
    238     } else {
    239       // Notify here as we won't be calling CommitPending (which does the
    240       // notify).
    241       delegate_->NotifySwappedFromRenderManager(
    242           NULL, render_frame_host_.get(), frame_tree_node_->IsMainFrame());
    243     }
    244   }
    245 
    246   // If entry includes the request ID of a request that is being transferred,
    247   // the destination render frame will take ownership, so release ownership of
    248   // the request.
    249   if (cross_site_transferring_request_.get() &&
    250       cross_site_transferring_request_->request_id() ==
    251           entry.transferred_global_request_id()) {
    252     cross_site_transferring_request_->ReleaseRequest();
    253   }
    254 
    255   return dest_render_frame_host;
    256 }
    257 
    258 void RenderFrameHostManager::Stop() {
    259   render_frame_host_->Stop();
    260 
    261   // If we are cross-navigating, we should stop the pending renderers.  This
    262   // will lead to a DidFailProvisionalLoad, which will properly destroy them.
    263   if (cross_navigation_pending_) {
    264     pending_render_frame_host_->Send(new FrameMsg_Stop(
    265         pending_render_frame_host_->GetRoutingID()));
    266   }
    267 }
    268 
    269 void RenderFrameHostManager::SetIsLoading(bool is_loading) {
    270   render_frame_host_->render_view_host()->SetIsLoading(is_loading);
    271   if (pending_render_frame_host_)
    272     pending_render_frame_host_->render_view_host()->SetIsLoading(is_loading);
    273 }
    274 
    275 bool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
    276   if (!cross_navigation_pending_)
    277     return true;
    278 
    279   // We should always have a pending RFH when there's a cross-process navigation
    280   // in progress.  Sanity check this for http://crbug.com/276333.
    281   CHECK(pending_render_frame_host_);
    282 
    283   // If the tab becomes unresponsive during {before}unload while doing a
    284   // cross-site navigation, proceed with the navigation.  (This assumes that
    285   // the pending RenderFrameHost is still responsive.)
    286   if (render_frame_host_->render_view_host()->IsWaitingForUnloadACK()) {
    287     // The request has been started and paused while we're waiting for the
    288     // unload handler to finish.  We'll pretend that it did.  The pending
    289     // renderer will then be swapped in as part of the usual DidNavigate logic.
    290     // (If the unload handler later finishes, this call will be ignored because
    291     // the pending_nav_params_ state will already be cleaned up.)
    292     current_host()->OnSwappedOut(true);
    293   } else if (render_frame_host_->render_view_host()->
    294                  is_waiting_for_beforeunload_ack()) {
    295     // Haven't gotten around to starting the request, because we're still
    296     // waiting for the beforeunload handler to finish.  We'll pretend that it
    297     // did finish, to let the navigation proceed.  Note that there's a danger
    298     // that the beforeunload handler will later finish and possibly return
    299     // false (meaning the navigation should not proceed), but we'll ignore it
    300     // in this case because it took too long.
    301     if (pending_render_frame_host_->are_navigations_suspended()) {
    302       pending_render_frame_host_->SetNavigationsSuspended(
    303           false, base::TimeTicks::Now());
    304     }
    305   }
    306   return false;
    307 }
    308 
    309 void RenderFrameHostManager::OnBeforeUnloadACK(
    310     bool for_cross_site_transition,
    311     bool proceed,
    312     const base::TimeTicks& proceed_time) {
    313   if (for_cross_site_transition) {
    314     // Ignore if we're not in a cross-site navigation.
    315     if (!cross_navigation_pending_)
    316       return;
    317 
    318     if (proceed) {
    319       // Ok to unload the current page, so proceed with the cross-site
    320       // navigation.  Note that if navigations are not currently suspended, it
    321       // might be because the renderer was deemed unresponsive and this call was
    322       // already made by ShouldCloseTabOnUnresponsiveRenderer.  In that case, it
    323       // is ok to do nothing here.
    324       if (pending_render_frame_host_ &&
    325           pending_render_frame_host_->are_navigations_suspended()) {
    326         pending_render_frame_host_->SetNavigationsSuspended(false,
    327                                                             proceed_time);
    328       }
    329     } else {
    330       // Current page says to cancel.
    331       CancelPending();
    332       cross_navigation_pending_ = false;
    333     }
    334   } else {
    335     // Non-cross site transition means closing the entire tab.
    336     bool proceed_to_fire_unload;
    337     delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
    338                                                   &proceed_to_fire_unload);
    339 
    340     if (proceed_to_fire_unload) {
    341       // If we're about to close the tab and there's a pending RFH, cancel it.
    342       // Otherwise, if the navigation in the pending RFH completes before the
    343       // close in the current RFH, we'll lose the tab close.
    344       if (pending_render_frame_host_) {
    345         CancelPending();
    346         cross_navigation_pending_ = false;
    347       }
    348 
    349       // This is not a cross-site navigation, the tab is being closed.
    350       render_frame_host_->render_view_host()->ClosePage();
    351     }
    352   }
    353 }
    354 
    355 void RenderFrameHostManager::OnCrossSiteResponse(
    356     RenderFrameHostImpl* pending_render_frame_host,
    357     const GlobalRequestID& global_request_id,
    358     scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
    359     const std::vector<GURL>& transfer_url_chain,
    360     const Referrer& referrer,
    361     ui::PageTransition page_transition,
    362     bool should_replace_current_entry) {
    363   // We should only get here for transfer navigations.  Most cross-process
    364   // navigations can just continue and wait to run the unload handler (by
    365   // swapping out) when the new navigation commits.
    366   CHECK(cross_site_transferring_request.get());
    367 
    368   // A transfer should only have come from our pending or current RFH.
    369   // TODO(creis): We need to handle the case that the pending RFH has changed
    370   // in the mean time, while this was being posted from the IO thread.  We
    371   // should probably cancel the request in that case.
    372   DCHECK(pending_render_frame_host == pending_render_frame_host_ ||
    373          pending_render_frame_host == render_frame_host_);
    374 
    375   // Store the transferring request so that we can release it if the transfer
    376   // navigation matches.
    377   cross_site_transferring_request_ = cross_site_transferring_request.Pass();
    378 
    379   // Sanity check that the params are for the correct frame and process.
    380   // These should match the RenderFrameHost that made the request.
    381   // If it started as a cross-process navigation via OpenURL, this is the
    382   // pending one.  If it wasn't cross-process until the transfer, this is the
    383   // current one.
    384   int render_frame_id = pending_render_frame_host_ ?
    385       pending_render_frame_host_->GetRoutingID() :
    386       render_frame_host_->GetRoutingID();
    387   DCHECK_EQ(render_frame_id, pending_render_frame_host->GetRoutingID());
    388   int process_id = pending_render_frame_host_ ?
    389       pending_render_frame_host_->GetProcess()->GetID() :
    390       render_frame_host_->GetProcess()->GetID();
    391   DCHECK_EQ(process_id, global_request_id.child_id);
    392 
    393   // Treat the last URL in the chain as the destination and the remainder as
    394   // the redirect chain.
    395   CHECK(transfer_url_chain.size());
    396   GURL transfer_url = transfer_url_chain.back();
    397   std::vector<GURL> rest_of_chain = transfer_url_chain;
    398   rest_of_chain.pop_back();
    399 
    400   // We don't know whether the original request had |user_action| set to true.
    401   // However, since we force the navigation to be in the current tab, it
    402   // doesn't matter.
    403   pending_render_frame_host->frame_tree_node()->navigator()->RequestTransferURL(
    404       pending_render_frame_host,
    405       transfer_url,
    406       rest_of_chain,
    407       referrer,
    408       page_transition,
    409       CURRENT_TAB,
    410       global_request_id,
    411       should_replace_current_entry,
    412       true);
    413 
    414   // The transferring request was only needed during the RequestTransferURL
    415   // call, so it is safe to clear at this point.
    416   cross_site_transferring_request_.reset();
    417 }
    418 
    419 void RenderFrameHostManager::OnDeferredAfterResponseStarted(
    420     const GlobalRequestID& global_request_id,
    421     RenderFrameHostImpl* pending_render_frame_host) {
    422   DCHECK(!response_started_id_.get());
    423 
    424   response_started_id_.reset(new GlobalRequestID(global_request_id));
    425 }
    426 
    427 void RenderFrameHostManager::ResumeResponseDeferredAtStart() {
    428   DCHECK(response_started_id_.get());
    429 
    430   RenderProcessHostImpl* process =
    431       static_cast<RenderProcessHostImpl*>(render_frame_host_->GetProcess());
    432   process->ResumeResponseDeferredAtStart(*response_started_id_);
    433 
    434   render_frame_host_->ClearPendingTransitionRequestData();
    435 
    436   response_started_id_.reset();
    437 }
    438 
    439 void RenderFrameHostManager::DidNavigateFrame(
    440     RenderFrameHostImpl* render_frame_host) {
    441   // PlzNavigate
    442   // The navigation request has been committed so the browser process doesn't
    443   // need to care about it anymore.
    444   if (CommandLine::ForCurrentProcess()->HasSwitch(
    445       switches::kEnableBrowserSideNavigation)) {
    446     navigation_request_.reset();
    447   }
    448 
    449   if (!cross_navigation_pending_) {
    450     DCHECK(!pending_render_frame_host_);
    451 
    452     // We should only hear this from our current renderer.
    453     DCHECK_EQ(render_frame_host_, render_frame_host);
    454 
    455     // Even when there is no pending RVH, there may be a pending Web UI.
    456     if (pending_web_ui())
    457       CommitPending();
    458     return;
    459   }
    460 
    461   if (render_frame_host == pending_render_frame_host_) {
    462     // The pending cross-site navigation completed, so show the renderer.
    463     CommitPending();
    464     cross_navigation_pending_ = false;
    465   } else if (render_frame_host == render_frame_host_) {
    466     // A navigation in the original page has taken place.  Cancel the pending
    467     // one.
    468     CancelPending();
    469     cross_navigation_pending_ = false;
    470   } else {
    471     // No one else should be sending us DidNavigate in this state.
    472     DCHECK(false);
    473   }
    474 }
    475 
    476 void RenderFrameHostManager::DidDisownOpener(
    477     RenderFrameHost* render_frame_host) {
    478   // Notify all RenderFrameHosts but the one that notified us. This is necessary
    479   // in case a process swap has occurred while the message was in flight.
    480   for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
    481        iter != proxy_hosts_.end();
    482        ++iter) {
    483     DCHECK_NE(iter->second->GetSiteInstance(),
    484               current_frame_host()->GetSiteInstance());
    485     iter->second->DisownOpener();
    486   }
    487 
    488   if (render_frame_host_.get() != render_frame_host)
    489     render_frame_host_->DisownOpener();
    490 
    491   if (pending_render_frame_host_ &&
    492       pending_render_frame_host_.get() != render_frame_host) {
    493     pending_render_frame_host_->DisownOpener();
    494   }
    495 }
    496 
    497 void RenderFrameHostManager::RendererProcessClosing(
    498     RenderProcessHost* render_process_host) {
    499   // Remove any swapped out RVHs from this process, so that we don't try to
    500   // swap them back in while the process is exiting.  Start by finding them,
    501   // since there could be more than one.
    502   std::list<int> ids_to_remove;
    503   for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
    504        iter != proxy_hosts_.end();
    505        ++iter) {
    506     if (iter->second->GetProcess() == render_process_host)
    507       ids_to_remove.push_back(iter->first);
    508   }
    509 
    510   // Now delete them.
    511   while (!ids_to_remove.empty()) {
    512     delete proxy_hosts_[ids_to_remove.back()];
    513     proxy_hosts_.erase(ids_to_remove.back());
    514     ids_to_remove.pop_back();
    515   }
    516 }
    517 
    518 void RenderFrameHostManager::SwapOutOldPage(
    519     RenderFrameHostImpl* old_render_frame_host) {
    520   TRACE_EVENT1("navigation", "RenderFrameHostManager::SwapOutOldPage",
    521                "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
    522   // Should only see this while we have a pending renderer.
    523   CHECK(cross_navigation_pending_);
    524 
    525   // Tell the renderer to suppress any further modal dialogs so that we can swap
    526   // it out.  This must be done before canceling any current dialog, in case
    527   // there is a loop creating additional dialogs.
    528   // TODO(creis): Handle modal dialogs in subframe processes.
    529   old_render_frame_host->render_view_host()->SuppressDialogsUntilSwapOut();
    530 
    531   // Now close any modal dialogs that would prevent us from swapping out.  This
    532   // must be done separately from SwapOut, so that the PageGroupLoadDeferrer is
    533   // no longer on the stack when we send the SwapOut message.
    534   delegate_->CancelModalDialogsForRenderManager();
    535 
    536   // Create the RenderFrameProxyHost that will replace the
    537   // RenderFrameHost which is swapping out. If one exists, ensure it is deleted
    538   // from the map and not leaked.
    539   DeleteRenderFrameProxyHost(old_render_frame_host->GetSiteInstance());
    540 
    541   RenderFrameProxyHost* proxy = new RenderFrameProxyHost(
    542       old_render_frame_host->GetSiteInstance(), frame_tree_node_);
    543   std::pair<RenderFrameProxyHostMap::iterator, bool> result =
    544       proxy_hosts_.insert(std::make_pair(
    545           old_render_frame_host->GetSiteInstance()->GetId(), proxy));
    546   CHECK(result.second) << "Inserting a duplicate item.";
    547 
    548   // Tell the old frame it is being swapped out.  This will fire the unload
    549   // handler in the background (without firing the beforeunload handler a second
    550   // time).  This is done right after we commit the new RenderFrameHost.
    551   old_render_frame_host->SwapOut(proxy);
    552 }
    553 
    554 void RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance(
    555     int32 site_instance_id,
    556     RenderFrameHostImpl* rfh) {
    557   RFHPendingDeleteMap::iterator iter =
    558       pending_delete_hosts_.find(site_instance_id);
    559   if (iter != pending_delete_hosts_.end() && iter->second.get() == rfh)
    560     pending_delete_hosts_.erase(site_instance_id);
    561 }
    562 
    563 void RenderFrameHostManager::ResetProxyHosts() {
    564   STLDeleteValues(&proxy_hosts_);
    565 }
    566 
    567 // PlzNavigate
    568 bool RenderFrameHostManager::RequestNavigation(
    569     const NavigationEntryImpl& entry,
    570     const FrameMsg_Navigate_Params& navigate_params) {
    571   CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
    572       switches::kEnableBrowserSideNavigation));
    573   if (render_frame_host_->IsRenderFrameLive()) {
    574     // TODO(clamy): send a RequestNavigation IPC.
    575     return true;
    576   }
    577 
    578   // The navigation request is sent directly to the IO thread.
    579   OnBeginNavigation(BeginNavigationFromNavigate(navigate_params));
    580   return true;
    581 }
    582 
    583 // PlzNavigate
    584 void RenderFrameHostManager::OnBeginNavigation(
    585     const FrameHostMsg_BeginNavigation_Params& params) {
    586   CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
    587       switches::kEnableBrowserSideNavigation));
    588   // TODO(clamy): Check if navigations are blocked and if so, return
    589   // immediately.
    590   NavigationRequestInfo info(params);
    591 
    592   info.first_party_for_cookies = frame_tree_node_->IsMainFrame() ?
    593       params.url : frame_tree_node_->frame_tree()->root()->current_url();
    594   info.is_main_frame = frame_tree_node_->IsMainFrame();
    595   info.parent_is_main_frame = !frame_tree_node_->parent() ?
    596       false : frame_tree_node_->parent()->IsMainFrame();
    597 
    598   // TODO(clamy): Check if the current RFH should be initialized (in case it has
    599   // crashed) not to display a sad tab while navigating.
    600   // TODO(clamy): Spawn a speculative renderer process if we do not have one to
    601   // use for the navigation.
    602 
    603   // If there is an ongoing request it must be canceled.
    604   if (navigation_request_.get())
    605     navigation_request_->CancelNavigation();
    606 
    607   navigation_request_.reset(new NavigationRequest(
    608       info, frame_tree_node_->frame_tree_node_id()));
    609   navigation_request_->BeginNavigation(params.request_body);
    610 }
    611 
    612 // PlzNavigate
    613 void RenderFrameHostManager::CommitNavigation(
    614     const NavigationBeforeCommitInfo& info) {
    615   CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
    616       switches::kEnableBrowserSideNavigation));
    617   DCHECK(navigation_request_.get());
    618   // Ignores navigation commits if the request ID doesn't match the current
    619   // active request.
    620   if (navigation_request_->navigation_request_id() !=
    621           info.navigation_request_id) {
    622     return;
    623   }
    624 
    625   // Pick the right RenderFrameHost to commit the navigation.
    626   SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
    627   // TODO(clamy): Replace the default values by the right ones. This may require
    628   // some storing in RequestNavigation.
    629   scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation(
    630       info.navigation_url,
    631       NULL,
    632       navigation_request_->info().navigation_params.transition_type,
    633       false,
    634       false);
    635   DCHECK(!pending_render_frame_host_.get());
    636 
    637   // TODO(clamy): Update how pending WebUI objects are handled.
    638   if (current_instance != new_instance.get()) {
    639     CreateRenderFrameHostForNewSiteInstance(
    640         current_instance, new_instance.get(), frame_tree_node_->IsMainFrame());
    641     DCHECK(pending_render_frame_host_.get());
    642     // TODO(clamy): Wait until the navigation has committed before swapping
    643     // renderers.
    644     scoped_ptr<RenderFrameHostImpl> old_render_frame_host =
    645         SetRenderFrameHost(pending_render_frame_host_.Pass());
    646     if (frame_tree_node_->IsMainFrame())
    647       render_frame_host_->render_view_host()->AttachToFrameTree();
    648   }
    649 
    650   // If the renderer that needs to navigate is not live (it was just created or
    651   // it crashed), initialize it.
    652   if (!render_frame_host_->render_view_host()->IsRenderViewLive()) {
    653     // Recreate the opener chain.
    654     int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
    655         render_frame_host_->GetSiteInstance());
    656     if (!InitRenderView(render_frame_host_->render_view_host(),
    657                         opener_route_id,
    658                         MSG_ROUTING_NONE,
    659                         frame_tree_node_->IsMainFrame())) {
    660       return;
    661     }
    662   }
    663 
    664   frame_tree_node_->navigator()->CommitNavigation(
    665       render_frame_host_.get(), info);
    666 }
    667 
    668 void RenderFrameHostManager::Observe(
    669     int type,
    670     const NotificationSource& source,
    671     const NotificationDetails& details) {
    672   switch (type) {
    673     case NOTIFICATION_RENDERER_PROCESS_CLOSED:
    674     case NOTIFICATION_RENDERER_PROCESS_CLOSING:
    675       RendererProcessClosing(
    676           Source<RenderProcessHost>(source).ptr());
    677       break;
    678 
    679     default:
    680       NOTREACHED();
    681   }
    682 }
    683 
    684 bool RenderFrameHostManager::ClearProxiesInSiteInstance(
    685     int32 site_instance_id,
    686     FrameTreeNode* node) {
    687   RenderFrameProxyHostMap::iterator iter =
    688       node->render_manager()->proxy_hosts_.find(site_instance_id);
    689   if (iter != node->render_manager()->proxy_hosts_.end()) {
    690     RenderFrameProxyHost* proxy = iter->second;
    691     // If the RVH is pending swap out, it needs to switch state to
    692     // pending shutdown. Otherwise it is deleted.
    693     if (proxy->GetRenderViewHost()->rvh_state() ==
    694         RenderViewHostImpl::STATE_PENDING_SWAP_OUT) {
    695       scoped_ptr<RenderFrameHostImpl> swapped_out_rfh =
    696           proxy->PassFrameHostOwnership();
    697 
    698       swapped_out_rfh->SetPendingShutdown(base::Bind(
    699           &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
    700           node->render_manager()->weak_factory_.GetWeakPtr(),
    701           site_instance_id,
    702           swapped_out_rfh.get()));
    703       RFHPendingDeleteMap::iterator pending_delete_iter =
    704           node->render_manager()->pending_delete_hosts_.find(site_instance_id);
    705       if (pending_delete_iter ==
    706               node->render_manager()->pending_delete_hosts_.end() ||
    707           pending_delete_iter->second.get() != swapped_out_rfh) {
    708         node->render_manager()->pending_delete_hosts_[site_instance_id] =
    709             linked_ptr<RenderFrameHostImpl>(swapped_out_rfh.release());
    710       }
    711     }
    712     delete proxy;
    713     node->render_manager()->proxy_hosts_.erase(site_instance_id);
    714   }
    715 
    716   return true;
    717 }
    718 
    719 bool RenderFrameHostManager::ShouldTransitionCrossSite() {
    720   // False in the single-process mode, as it makes RVHs to accumulate
    721   // in swapped_out_hosts_.
    722   // True if we are using process-per-site-instance (default) or
    723   // process-per-site (kProcessPerSite).
    724   return
    725       !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
    726       !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab);
    727 }
    728 
    729 bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
    730     const GURL& current_effective_url,
    731     bool current_is_view_source_mode,
    732     SiteInstance* new_site_instance,
    733     const GURL& new_effective_url,
    734     bool new_is_view_source_mode) const {
    735   // If new_entry already has a SiteInstance, assume it is correct.  We only
    736   // need to force a swap if it is in a different BrowsingInstance.
    737   if (new_site_instance) {
    738     return !new_site_instance->IsRelatedSiteInstance(
    739         render_frame_host_->GetSiteInstance());
    740   }
    741 
    742   // Check for reasons to swap processes even if we are in a process model that
    743   // doesn't usually swap (e.g., process-per-tab).  Any time we return true,
    744   // the new_entry will be rendered in a new SiteInstance AND BrowsingInstance.
    745   BrowserContext* browser_context =
    746       delegate_->GetControllerForRenderManager().GetBrowserContext();
    747 
    748   // Don't force a new BrowsingInstance for debug URLs that are handled in the
    749   // renderer process, like javascript: or chrome://crash.
    750   if (IsRendererDebugURL(new_effective_url))
    751     return false;
    752 
    753   // For security, we should transition between processes when one is a Web UI
    754   // page and one isn't.
    755   if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
    756           browser_context, current_effective_url)) {
    757     // If so, force a swap if destination is not an acceptable URL for Web UI.
    758     // Here, data URLs are never allowed.
    759     if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
    760             browser_context, new_effective_url)) {
    761       return true;
    762     }
    763   } else {
    764     // Force a swap if it's a Web UI URL.
    765     if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
    766             browser_context, new_effective_url)) {
    767       return true;
    768     }
    769   }
    770 
    771   // Check with the content client as well.  Important to pass
    772   // current_effective_url here, which uses the SiteInstance's site if there is
    773   // no current_entry.
    774   if (GetContentClient()->browser()->ShouldSwapBrowsingInstancesForNavigation(
    775           render_frame_host_->GetSiteInstance(),
    776           current_effective_url, new_effective_url)) {
    777     return true;
    778   }
    779 
    780   // We can't switch a RenderView between view source and non-view source mode
    781   // without screwing up the session history sometimes (when navigating between
    782   // "view-source:http://foo.com/" and "http://foo.com/", Blink doesn't treat
    783   // it as a new navigation). So require a BrowsingInstance switch.
    784   if (current_is_view_source_mode != new_is_view_source_mode)
    785     return true;
    786 
    787   return false;
    788 }
    789 
    790 bool RenderFrameHostManager::ShouldReuseWebUI(
    791     const NavigationEntry* current_entry,
    792     const NavigationEntryImpl* new_entry) const {
    793   NavigationControllerImpl& controller =
    794       delegate_->GetControllerForRenderManager();
    795   return current_entry && web_ui_.get() &&
    796       (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
    797           controller.GetBrowserContext(), current_entry->GetURL()) ==
    798        WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
    799           controller.GetBrowserContext(), new_entry->GetURL()));
    800 }
    801 
    802 SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation(
    803     const GURL& dest_url,
    804     SiteInstance* dest_instance,
    805     ui::PageTransition dest_transition,
    806     bool dest_is_restore,
    807     bool dest_is_view_source_mode) {
    808   SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
    809   SiteInstance* new_instance = current_instance;
    810 
    811   // We do not currently swap processes for navigations in webview tag guests.
    812   bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme);
    813 
    814   // Determine if we need a new BrowsingInstance for this entry.  If true, this
    815   // implies that it will get a new SiteInstance (and likely process), and that
    816   // other tabs in the current BrowsingInstance will be unable to script it.
    817   // This is used for cases that require a process swap even in the
    818   // process-per-tab model, such as WebUI pages.
    819   // TODO(clamy): Remove the dependency on the current entry.
    820   const NavigationEntry* current_entry =
    821       delegate_->GetLastCommittedNavigationEntryForRenderManager();
    822   BrowserContext* browser_context =
    823       delegate_->GetControllerForRenderManager().GetBrowserContext();
    824   const GURL& current_effective_url = current_entry ?
    825       SiteInstanceImpl::GetEffectiveURL(browser_context,
    826                                         current_entry->GetURL()) :
    827       render_frame_host_->GetSiteInstance()->GetSiteURL();
    828   bool current_is_view_source_mode = current_entry ?
    829       current_entry->IsViewSourceMode() : dest_is_view_source_mode;
    830   bool force_swap = !is_guest_scheme &&
    831       ShouldSwapBrowsingInstancesForNavigation(
    832           current_effective_url,
    833           current_is_view_source_mode,
    834           dest_instance,
    835           SiteInstanceImpl::GetEffectiveURL(browser_context, dest_url),
    836           dest_is_view_source_mode);
    837   if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap)) {
    838     new_instance = GetSiteInstanceForURL(
    839         dest_url,
    840         dest_instance,
    841         dest_transition,
    842         dest_is_restore,
    843         dest_is_view_source_mode,
    844         current_instance,
    845         force_swap);
    846   }
    847 
    848   // If force_swap is true, we must use a different SiteInstance.  If we didn't,
    849   // we would have two RenderFrameHosts in the same SiteInstance and the same
    850   // frame, resulting in page_id conflicts for their NavigationEntries.
    851   if (force_swap)
    852     CHECK_NE(new_instance, current_instance);
    853   return new_instance;
    854 }
    855 
    856 SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
    857     const GURL& dest_url,
    858     SiteInstance* dest_instance,
    859     ui::PageTransition dest_transition,
    860     bool dest_is_restore,
    861     bool dest_is_view_source_mode,
    862     SiteInstance* current_instance,
    863     bool force_browsing_instance_swap) {
    864   NavigationControllerImpl& controller =
    865       delegate_->GetControllerForRenderManager();
    866   BrowserContext* browser_context = controller.GetBrowserContext();
    867 
    868   // If the entry has an instance already we should use it.
    869   if (dest_instance) {
    870     // If we are forcing a swap, this should be in a different BrowsingInstance.
    871     if (force_browsing_instance_swap) {
    872       CHECK(!dest_instance->IsRelatedSiteInstance(
    873                 render_frame_host_->GetSiteInstance()));
    874     }
    875     return dest_instance;
    876   }
    877 
    878   // If a swap is required, we need to force the SiteInstance AND
    879   // BrowsingInstance to be different ones, using CreateForURL.
    880   if (force_browsing_instance_swap)
    881     return SiteInstance::CreateForURL(browser_context, dest_url);
    882 
    883   // (UGLY) HEURISTIC, process-per-site only:
    884   //
    885   // If this navigation is generated, then it probably corresponds to a search
    886   // query.  Given that search results typically lead to users navigating to
    887   // other sites, we don't really want to use the search engine hostname to
    888   // determine the site instance for this navigation.
    889   //
    890   // NOTE: This can be removed once we have a way to transition between
    891   //       RenderViews in response to a link click.
    892   //
    893   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) &&
    894       ui::PageTransitionCoreTypeIs(
    895           dest_transition, ui::PAGE_TRANSITION_GENERATED)) {
    896     return current_instance;
    897   }
    898 
    899   SiteInstanceImpl* current_site_instance =
    900       static_cast<SiteInstanceImpl*>(current_instance);
    901 
    902   // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it
    903   // for this entry.  We won't commit the SiteInstance to this site until the
    904   // navigation commits (in DidNavigate), unless the navigation entry was
    905   // restored or it's a Web UI as described below.
    906   if (!current_site_instance->HasSite()) {
    907     // If we've already created a SiteInstance for our destination, we don't
    908     // want to use this unused SiteInstance; use the existing one.  (We don't
    909     // do this check if the current_instance has a site, because for now, we
    910     // want to compare against the current URL and not the SiteInstance's site.
    911     // In this case, there is no current URL, so comparing against the site is
    912     // ok.  See additional comments below.)
    913     //
    914     // Also, if the URL should use process-per-site mode and there is an
    915     // existing process for the site, we should use it.  We can call
    916     // GetRelatedSiteInstance() for this, which will eagerly set the site and
    917     // thus use the correct process.
    918     bool use_process_per_site =
    919         RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
    920         RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
    921     if (current_site_instance->HasRelatedSiteInstance(dest_url) ||
    922         use_process_per_site) {
    923       return current_site_instance->GetRelatedSiteInstance(dest_url);
    924     }
    925 
    926     // For extensions, Web UI URLs (such as the new tab page), and apps we do
    927     // not want to use the current_instance if it has no site, since it will
    928     // have a RenderProcessHost of PRIV_NORMAL.  Create a new SiteInstance for
    929     // this URL instead (with the correct process type).
    930     if (current_site_instance->HasWrongProcessForURL(dest_url))
    931       return current_site_instance->GetRelatedSiteInstance(dest_url);
    932 
    933     // View-source URLs must use a new SiteInstance and BrowsingInstance.
    934     // TODO(nasko): This is the same condition as later in the function. This
    935     // should be taken into account when refactoring this method as part of
    936     // http://crbug.com/123007.
    937     if (dest_is_view_source_mode)
    938       return SiteInstance::CreateForURL(browser_context, dest_url);
    939 
    940     // If we are navigating from a blank SiteInstance to a WebUI, make sure we
    941     // create a new SiteInstance.
    942     if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
    943             browser_context, dest_url)) {
    944         return SiteInstance::CreateForURL(browser_context, dest_url);
    945     }
    946 
    947     // Normally the "site" on the SiteInstance is set lazily when the load
    948     // actually commits. This is to support better process sharing in case
    949     // the site redirects to some other site: we want to use the destination
    950     // site in the site instance.
    951     //
    952     // In the case of session restore, as it loads all the pages immediately
    953     // we need to set the site first, otherwise after a restore none of the
    954     // pages would share renderers in process-per-site.
    955     //
    956     // The embedder can request some urls never to be assigned to SiteInstance
    957     // through the ShouldAssignSiteForURL() content client method, so that
    958     // renderers created for particular chrome urls (e.g. the chrome-native://
    959     // scheme) can be reused for subsequent navigations in the same WebContents.
    960     // See http://crbug.com/386542.
    961     if (dest_is_restore &&
    962         GetContentClient()->browser()->ShouldAssignSiteForURL(dest_url)) {
    963       current_site_instance->SetSite(dest_url);
    964     }
    965 
    966     return current_site_instance;
    967   }
    968 
    969   // Otherwise, only create a new SiteInstance for a cross-site navigation.
    970 
    971   // TODO(creis): Once we intercept links and script-based navigations, we
    972   // will be able to enforce that all entries in a SiteInstance actually have
    973   // the same site, and it will be safe to compare the URL against the
    974   // SiteInstance's site, as follows:
    975   // const GURL& current_url = current_instance->site();
    976   // For now, though, we're in a hybrid model where you only switch
    977   // SiteInstances if you type in a cross-site URL.  This means we have to
    978   // compare the entry's URL to the last committed entry's URL.
    979   NavigationEntry* current_entry = controller.GetLastCommittedEntry();
    980   if (interstitial_page_) {
    981     // The interstitial is currently the last committed entry, but we want to
    982     // compare against the last non-interstitial entry.
    983     current_entry = controller.GetEntryAtOffset(-1);
    984   }
    985   // If there is no last non-interstitial entry (and current_instance already
    986   // has a site), then we must have been opened from another tab.  We want
    987   // to compare against the URL of the page that opened us, but we can't
    988   // get to it directly.  The best we can do is check against the site of
    989   // the SiteInstance.  This will be correct when we intercept links and
    990   // script-based navigations, but for now, it could place some pages in a
    991   // new process unnecessarily.  We should only hit this case if a page tries
    992   // to open a new tab to an interstitial-inducing URL, and then navigates
    993   // the page to a different same-site URL.  (This seems very unlikely in
    994   // practice.)
    995   const GURL& current_url = (current_entry) ? current_entry->GetURL() :
    996       current_instance->GetSiteURL();
    997 
    998   // View-source URLs must use a new SiteInstance and BrowsingInstance.
    999   // We don't need a swap when going from view-source to a debug URL like
   1000   // chrome://crash, however.
   1001   // TODO(creis): Refactor this method so this duplicated code isn't needed.
   1002   // See http://crbug.com/123007.
   1003   if (current_entry &&
   1004       current_entry->IsViewSourceMode() != dest_is_view_source_mode &&
   1005       !IsRendererDebugURL(dest_url)) {
   1006     return SiteInstance::CreateForURL(browser_context, dest_url);
   1007   }
   1008 
   1009   // Use the current SiteInstance for same site navigations, as long as the
   1010   // process type is correct.  (The URL may have been installed as an app since
   1011   // the last time we visited it.)
   1012   if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
   1013       !current_site_instance->HasWrongProcessForURL(dest_url)) {
   1014     return current_instance;
   1015   }
   1016 
   1017   // Start the new renderer in a new SiteInstance, but in the current
   1018   // BrowsingInstance.  It is important to immediately give this new
   1019   // SiteInstance to a RenderViewHost (if it is different than our current
   1020   // SiteInstance), so that it is ref counted.  This will happen in
   1021   // CreateRenderView.
   1022   return current_instance->GetRelatedSiteInstance(dest_url);
   1023 }
   1024 
   1025 void RenderFrameHostManager::CreateRenderFrameHostForNewSiteInstance(
   1026     SiteInstance* old_instance,
   1027     SiteInstance* new_instance,
   1028     bool is_main_frame) {
   1029   // Ensure that we have created RFHs for the new RFH's opener chain if
   1030   // we are staying in the same BrowsingInstance. This allows the new RFH
   1031   // to send cross-process script calls to its opener(s).
   1032   int opener_route_id = MSG_ROUTING_NONE;
   1033   if (new_instance->IsRelatedSiteInstance(old_instance)) {
   1034     opener_route_id =
   1035         delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
   1036     if (CommandLine::ForCurrentProcess()->HasSwitch(
   1037             switches::kSitePerProcess)) {
   1038       // Ensure that the frame tree has RenderFrameProxyHosts for the new
   1039       // SiteInstance in all nodes except the current one.
   1040       frame_tree_node_->frame_tree()->CreateProxiesForSiteInstance(
   1041           frame_tree_node_, new_instance);
   1042     }
   1043   }
   1044 
   1045   // Create a non-swapped-out RFH with the given opener.
   1046   int route_id = CreateRenderFrame(
   1047       new_instance, opener_route_id, false, is_main_frame,
   1048       delegate_->IsHidden());
   1049   if (route_id == MSG_ROUTING_NONE) {
   1050     pending_render_frame_host_.reset();
   1051     return;
   1052   }
   1053 }
   1054 
   1055 scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
   1056     SiteInstance* site_instance,
   1057     int view_routing_id,
   1058     int frame_routing_id,
   1059     bool swapped_out,
   1060     bool hidden) {
   1061   if (frame_routing_id == MSG_ROUTING_NONE)
   1062     frame_routing_id = site_instance->GetProcess()->GetNextRoutingID();
   1063 
   1064   // Create a RVH for main frames, or find the existing one for subframes.
   1065   FrameTree* frame_tree = frame_tree_node_->frame_tree();
   1066   RenderViewHostImpl* render_view_host = NULL;
   1067   if (frame_tree_node_->IsMainFrame()) {
   1068     render_view_host = frame_tree->CreateRenderViewHost(
   1069         site_instance, view_routing_id, frame_routing_id, swapped_out, hidden);
   1070   } else {
   1071     render_view_host = frame_tree->GetRenderViewHost(site_instance);
   1072 
   1073     CHECK(render_view_host);
   1074   }
   1075 
   1076   // TODO(creis): Pass hidden to RFH.
   1077   scoped_ptr<RenderFrameHostImpl> render_frame_host =
   1078       make_scoped_ptr(RenderFrameHostFactory::Create(render_view_host,
   1079                                                      render_frame_delegate_,
   1080                                                      frame_tree,
   1081                                                      frame_tree_node_,
   1082                                                      frame_routing_id,
   1083                                                      swapped_out).release());
   1084   return render_frame_host.Pass();
   1085 }
   1086 
   1087 int RenderFrameHostManager::CreateRenderFrame(SiteInstance* instance,
   1088                                               int opener_route_id,
   1089                                               bool swapped_out,
   1090                                               bool for_main_frame_navigation,
   1091                                               bool hidden) {
   1092   CHECK(instance);
   1093   DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
   1094 
   1095   // TODO(nasko): Remove the following CHECK once cross-site navigation no
   1096   // longer relies on swapped out RFH for the top-level frame.
   1097   if (!frame_tree_node_->IsMainFrame()) {
   1098     CHECK(!swapped_out);
   1099   }
   1100 
   1101   scoped_ptr<RenderFrameHostImpl> new_render_frame_host;
   1102   RenderFrameHostImpl* frame_to_announce = NULL;
   1103   int routing_id = MSG_ROUTING_NONE;
   1104 
   1105   // We are creating a pending or swapped out RFH here.  We should never create
   1106   // it in the same SiteInstance as our current RFH.
   1107   CHECK_NE(render_frame_host_->GetSiteInstance(), instance);
   1108 
   1109   // Check if we've already created an RFH for this SiteInstance.  If so, try
   1110   // to re-use the existing one, which has already been initialized.  We'll
   1111   // remove it from the list of proxy hosts below if it will be active.
   1112   RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
   1113 
   1114   if (proxy && proxy->render_frame_host()) {
   1115     routing_id = proxy->GetRenderViewHost()->GetRoutingID();
   1116     // Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost.
   1117     // Prevent the process from exiting while we're trying to use it.
   1118     if (!swapped_out) {
   1119       new_render_frame_host = proxy->PassFrameHostOwnership();
   1120       new_render_frame_host->GetProcess()->AddPendingView();
   1121 
   1122       proxy_hosts_.erase(instance->GetId());
   1123       delete proxy;
   1124 
   1125       // When a new render view is created by the renderer, the new WebContents
   1126       // gets a RenderViewHost in the SiteInstance of its opener WebContents.
   1127       // If not used in the first navigation, this RVH is swapped out and is not
   1128       // granted bindings, so we may need to grant them when swapping it in.
   1129       if (pending_web_ui() &&
   1130           !new_render_frame_host->GetProcess()->IsIsolatedGuest()) {
   1131         int required_bindings = pending_web_ui()->GetBindings();
   1132         RenderViewHost* rvh = new_render_frame_host->render_view_host();
   1133         if ((rvh->GetEnabledBindings() & required_bindings) !=
   1134                 required_bindings) {
   1135           rvh->AllowBindings(required_bindings);
   1136         }
   1137       }
   1138     }
   1139   } else {
   1140     // Create a new RenderFrameHost if we don't find an existing one.
   1141     new_render_frame_host = CreateRenderFrameHost(
   1142         instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, swapped_out, hidden);
   1143     RenderViewHostImpl* render_view_host =
   1144         new_render_frame_host->render_view_host();
   1145     int proxy_routing_id = MSG_ROUTING_NONE;
   1146 
   1147     // Prevent the process from exiting while we're trying to navigate in it.
   1148     // Otherwise, if the new RFH is swapped out already, store it.
   1149     if (!swapped_out) {
   1150       new_render_frame_host->GetProcess()->AddPendingView();
   1151     } else {
   1152       proxy = new RenderFrameProxyHost(
   1153           new_render_frame_host->GetSiteInstance(), frame_tree_node_);
   1154       proxy_hosts_[instance->GetId()] = proxy;
   1155       proxy_routing_id = proxy->GetRoutingID();
   1156       if (frame_tree_node_->IsMainFrame())
   1157         proxy->TakeFrameHostOwnership(new_render_frame_host.Pass());
   1158     }
   1159 
   1160     bool success = InitRenderView(render_view_host,
   1161                                   opener_route_id,
   1162                                   proxy_routing_id,
   1163                                   for_main_frame_navigation);
   1164     if (success) {
   1165       if (frame_tree_node_->IsMainFrame()) {
   1166         // Don't show the main frame's view until we get a DidNavigate from it.
   1167         render_view_host->GetView()->Hide();
   1168       } else if (!swapped_out) {
   1169         // Init the RFH, so a RenderFrame is created in the renderer.
   1170         DCHECK(new_render_frame_host.get());
   1171         success = InitRenderFrame(new_render_frame_host.get());
   1172       }
   1173       if (swapped_out) {
   1174         proxy_hosts_[instance->GetId()]->InitRenderFrameProxy();
   1175       }
   1176     } else if (!swapped_out && pending_render_frame_host_) {
   1177       CancelPending();
   1178     }
   1179     routing_id = render_view_host->GetRoutingID();
   1180     frame_to_announce = new_render_frame_host.get();
   1181   }
   1182 
   1183   // Use this as our new pending RFH if it isn't swapped out.
   1184   if (!swapped_out)
   1185     pending_render_frame_host_ = new_render_frame_host.Pass();
   1186 
   1187   // If a brand new RFH was created, announce it to observers.
   1188   if (frame_to_announce)
   1189     render_frame_delegate_->RenderFrameCreated(frame_to_announce);
   1190 
   1191   return routing_id;
   1192 }
   1193 
   1194 int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance) {
   1195   // A RenderFrameProxyHost should never be created in the same SiteInstance as
   1196   // the current RFH.
   1197   CHECK(instance);
   1198   CHECK_NE(instance, render_frame_host_->GetSiteInstance());
   1199 
   1200   RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
   1201   if (proxy)
   1202     return proxy->GetRoutingID();
   1203 
   1204   proxy = new RenderFrameProxyHost(instance, frame_tree_node_);
   1205   proxy_hosts_[instance->GetId()] = proxy;
   1206   proxy->InitRenderFrameProxy();
   1207   return proxy->GetRoutingID();
   1208 }
   1209 
   1210 bool RenderFrameHostManager::InitRenderView(
   1211     RenderViewHostImpl* render_view_host,
   1212     int opener_route_id,
   1213     int proxy_routing_id,
   1214     bool for_main_frame_navigation) {
   1215   // We may have initialized this RenderViewHost for another RenderFrameHost.
   1216   if (render_view_host->IsRenderViewLive())
   1217     return true;
   1218 
   1219   // If the pending navigation is to a WebUI and the RenderView is not in a
   1220   // guest process, tell the RenderViewHost about any bindings it will need
   1221   // enabled.
   1222   if (pending_web_ui() && !render_view_host->GetProcess()->IsIsolatedGuest()) {
   1223     render_view_host->AllowBindings(pending_web_ui()->GetBindings());
   1224   } else {
   1225     // Ensure that we don't create an unprivileged RenderView in a WebUI-enabled
   1226     // process unless it's swapped out.
   1227     if (!render_view_host->IsSwappedOut()) {
   1228       CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
   1229                 render_view_host->GetProcess()->GetID()));
   1230     }
   1231   }
   1232 
   1233   return delegate_->CreateRenderViewForRenderManager(render_view_host,
   1234                                                      opener_route_id,
   1235                                                      proxy_routing_id,
   1236                                                      for_main_frame_navigation);
   1237 }
   1238 
   1239 bool RenderFrameHostManager::InitRenderFrame(
   1240     RenderFrameHostImpl* render_frame_host) {
   1241   if (render_frame_host->IsRenderFrameLive())
   1242     return true;
   1243 
   1244   int parent_routing_id = MSG_ROUTING_NONE;
   1245   if (frame_tree_node_->parent()) {
   1246     parent_routing_id = frame_tree_node_->parent()->render_manager()->
   1247         GetRoutingIdForSiteInstance(render_frame_host->GetSiteInstance());
   1248     CHECK_NE(parent_routing_id, MSG_ROUTING_NONE);
   1249   }
   1250   return delegate_->CreateRenderFrameForRenderManager(render_frame_host,
   1251                                                       parent_routing_id);
   1252 }
   1253 
   1254 int RenderFrameHostManager::GetRoutingIdForSiteInstance(
   1255     SiteInstance* site_instance) {
   1256   if (render_frame_host_->GetSiteInstance() == site_instance)
   1257     return render_frame_host_->GetRoutingID();
   1258 
   1259   RenderFrameProxyHostMap::iterator iter =
   1260       proxy_hosts_.find(site_instance->GetId());
   1261   if (iter != proxy_hosts_.end())
   1262     return iter->second->GetRoutingID();
   1263 
   1264   return MSG_ROUTING_NONE;
   1265 }
   1266 
   1267 void RenderFrameHostManager::CommitPending() {
   1268   TRACE_EVENT1("navigation", "RenderFrameHostManager::CommitPending",
   1269                "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
   1270   // First check whether we're going to want to focus the location bar after
   1271   // this commit.  We do this now because the navigation hasn't formally
   1272   // committed yet, so if we've already cleared |pending_web_ui_| the call chain
   1273   // this triggers won't be able to figure out what's going on.
   1274   bool will_focus_location_bar = delegate_->FocusLocationBarByDefault();
   1275 
   1276   // Next commit the Web UI, if any. Either replace |web_ui_| with
   1277   // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or
   1278   // leave |web_ui_| as is if reusing it.
   1279   DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get()));
   1280   if (pending_web_ui_) {
   1281     web_ui_.reset(pending_web_ui_.release());
   1282   } else if (!pending_and_current_web_ui_.get()) {
   1283     web_ui_.reset();
   1284   } else {
   1285     DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get());
   1286     pending_and_current_web_ui_.reset();
   1287   }
   1288 
   1289   // It's possible for the pending_render_frame_host_ to be NULL when we aren't
   1290   // crossing process boundaries. If so, we just needed to handle the Web UI
   1291   // committing above and we're done.
   1292   if (!pending_render_frame_host_) {
   1293     if (will_focus_location_bar)
   1294       delegate_->SetFocusToLocationBar(false);
   1295     return;
   1296   }
   1297 
   1298   // Remember if the page was focused so we can focus the new renderer in
   1299   // that case.
   1300   bool focus_render_view = !will_focus_location_bar &&
   1301       render_frame_host_->render_view_host()->GetView() &&
   1302       render_frame_host_->render_view_host()->GetView()->HasFocus();
   1303 
   1304   // TODO(creis): As long as show/hide are on RVH, we don't want to do them for
   1305   // subframe navigations or they'll interfere with the top-level page.
   1306   bool is_main_frame = frame_tree_node_->IsMainFrame();
   1307 
   1308   // Swap in the pending frame and make it active. Also ensure the FrameTree
   1309   // stays in sync.
   1310   scoped_ptr<RenderFrameHostImpl> old_render_frame_host =
   1311       SetRenderFrameHost(pending_render_frame_host_.Pass());
   1312   if (is_main_frame)
   1313     render_frame_host_->render_view_host()->AttachToFrameTree();
   1314 
   1315   // The process will no longer try to exit, so we can decrement the count.
   1316   render_frame_host_->GetProcess()->RemovePendingView();
   1317 
   1318   // If the view is gone, then this RenderViewHost died while it was hidden.
   1319   // We ignored the RenderProcessGone call at the time, so we should send it now
   1320   // to make sure the sad tab shows up, etc.
   1321   if (!render_frame_host_->render_view_host()->GetView()) {
   1322     delegate_->RenderProcessGoneFromRenderManager(
   1323         render_frame_host_->render_view_host());
   1324   } else if (!delegate_->IsHidden()) {
   1325     render_frame_host_->render_view_host()->GetView()->Show();
   1326   }
   1327 
   1328   // If the old frame is live, swap it out now that the new frame is visible.
   1329   int32 old_site_instance_id =
   1330       old_render_frame_host->GetSiteInstance()->GetId();
   1331   if (old_render_frame_host->IsRenderFrameLive()) {
   1332     SwapOutOldPage(old_render_frame_host.get());
   1333 
   1334     // Schedule the old frame to shut down after it swaps out, if there are no
   1335     // other active views in its SiteInstance.
   1336     if (!static_cast<SiteInstanceImpl*>(
   1337             old_render_frame_host->GetSiteInstance())->active_view_count()) {
   1338       old_render_frame_host->render_view_host()->SetPendingShutdown(base::Bind(
   1339           &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
   1340           weak_factory_.GetWeakPtr(),
   1341           old_site_instance_id,
   1342           old_render_frame_host.get()));
   1343     }
   1344   }
   1345 
   1346   // For top-level frames, also hide the old RenderViewHost's view.
   1347   if (is_main_frame && old_render_frame_host->render_view_host()->GetView())
   1348     old_render_frame_host->render_view_host()->GetView()->Hide();
   1349 
   1350   // Make sure the size is up to date.  (Fix for bug 1079768.)
   1351   delegate_->UpdateRenderViewSizeForRenderManager();
   1352 
   1353   if (will_focus_location_bar) {
   1354     delegate_->SetFocusToLocationBar(false);
   1355   } else if (focus_render_view &&
   1356              render_frame_host_->render_view_host()->GetView()) {
   1357     render_frame_host_->render_view_host()->GetView()->Focus();
   1358   }
   1359 
   1360   // Notify that we've swapped RenderFrameHosts. We do this before shutting down
   1361   // the RFH so that we can clean up RendererResources related to the RFH first.
   1362   delegate_->NotifySwappedFromRenderManager(
   1363       old_render_frame_host.get(), render_frame_host_.get(), is_main_frame);
   1364 
   1365   // If the old RFH is not live, just return as there is no further work to do.
   1366   if (!old_render_frame_host->IsRenderFrameLive())
   1367     return;
   1368 
   1369   // If the old RFH is live, we are swapping it out and should keep track of
   1370   // it in case we navigate back to it, or it is waiting for the unload event
   1371   // to execute in the background.
   1372   // TODO(creis): Swap out the subframe in --site-per-process.
   1373   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) {
   1374     DCHECK(old_render_frame_host->is_swapped_out() ||
   1375            !RenderViewHostImpl::IsRVHStateActive(
   1376                old_render_frame_host->render_view_host()->rvh_state()));
   1377   }
   1378 
   1379   // If the RenderViewHost backing the RenderFrameHost is pending shutdown,
   1380   // the RenderFrameHost should be put in the map of RenderFrameHosts pending
   1381   // shutdown. Otherwise, it is stored in the map of proxy hosts.
   1382   if (old_render_frame_host->render_view_host()->rvh_state() ==
   1383       RenderViewHostImpl::STATE_PENDING_SHUTDOWN) {
   1384     // The proxy for this RenderFrameHost is created when sending the
   1385     // SwapOut message, so check if it already exists and delete it.
   1386     RenderFrameProxyHostMap::iterator iter =
   1387         proxy_hosts_.find(old_site_instance_id);
   1388     if (iter != proxy_hosts_.end()) {
   1389       delete iter->second;
   1390       proxy_hosts_.erase(iter);
   1391     }
   1392     RFHPendingDeleteMap::iterator pending_delete_iter =
   1393         pending_delete_hosts_.find(old_site_instance_id);
   1394     if (pending_delete_iter == pending_delete_hosts_.end() ||
   1395         pending_delete_iter->second.get() != old_render_frame_host) {
   1396       pending_delete_hosts_[old_site_instance_id] =
   1397           linked_ptr<RenderFrameHostImpl>(old_render_frame_host.release());
   1398     }
   1399   } else {
   1400     CHECK(proxy_hosts_.find(render_frame_host_->GetSiteInstance()->GetId()) ==
   1401           proxy_hosts_.end());
   1402 
   1403     // Capture the active view count on the old RFH SiteInstance, since the
   1404     // ownership might be passed into the proxy and the pointer will be
   1405     // invalid.
   1406     int active_view_count =
   1407         static_cast<SiteInstanceImpl*>(old_render_frame_host->GetSiteInstance())
   1408             ->active_view_count();
   1409 
   1410     if (is_main_frame) {
   1411       RenderFrameProxyHostMap::iterator iter =
   1412           proxy_hosts_.find(old_site_instance_id);
   1413       CHECK(iter != proxy_hosts_.end());
   1414       iter->second->TakeFrameHostOwnership(old_render_frame_host.Pass());
   1415     }
   1416 
   1417     // If there are no active views in this SiteInstance, it means that
   1418     // this RFH was the last active one in the SiteInstance. Now that we
   1419     // know that all RFHs are swapped out, we can delete all the RFPHs and
   1420     // RVHs in this SiteInstance.
   1421     if (!active_view_count) {
   1422       ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id);
   1423     } else {
   1424       // If this is a subframe, it should have a CrossProcessFrameConnector
   1425       // created already and we just need to link it to the proper view in the
   1426       // new process.
   1427       if (!is_main_frame) {
   1428         RenderFrameProxyHost* proxy = GetProxyToParent();
   1429         if (proxy) {
   1430           proxy->SetChildRWHView(
   1431               render_frame_host_->render_view_host()->GetView());
   1432         }
   1433       }
   1434     }
   1435   }
   1436 }
   1437 
   1438 void RenderFrameHostManager::ShutdownRenderFrameProxyHostsInSiteInstance(
   1439     int32 site_instance_id) {
   1440   // First remove any swapped out RFH for this SiteInstance from our own list.
   1441   ClearProxiesInSiteInstance(site_instance_id, frame_tree_node_);
   1442 
   1443   // Use the safe RenderWidgetHost iterator for now to find all RenderViewHosts
   1444   // in the SiteInstance, then tell their respective FrameTrees to remove all
   1445   // RenderFrameProxyHosts corresponding to them.
   1446   // TODO(creis): Replace this with a RenderFrameHostIterator that protects
   1447   // against use-after-frees if a later element is deleted before getting to it.
   1448   scoped_ptr<RenderWidgetHostIterator> widgets(
   1449       RenderWidgetHostImpl::GetAllRenderWidgetHosts());
   1450   while (RenderWidgetHost* widget = widgets->GetNextHost()) {
   1451     if (!widget->IsRenderView())
   1452       continue;
   1453     RenderViewHostImpl* rvh =
   1454         static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget));
   1455     if (site_instance_id == rvh->GetSiteInstance()->GetId()) {
   1456       // This deletes all RenderFrameHosts using the |rvh|, which then causes
   1457       // |rvh| to Shutdown.
   1458       FrameTree* tree = rvh->GetDelegate()->GetFrameTree();
   1459       tree->ForEach(base::Bind(
   1460           &RenderFrameHostManager::ClearProxiesInSiteInstance,
   1461           site_instance_id));
   1462     }
   1463   }
   1464 }
   1465 
   1466 RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
   1467     const NavigationEntryImpl& entry) {
   1468   // If we are currently navigating cross-process, we want to get back to normal
   1469   // and then navigate as usual.
   1470   if (cross_navigation_pending_) {
   1471     if (pending_render_frame_host_)
   1472       CancelPending();
   1473     cross_navigation_pending_ = false;
   1474   }
   1475 
   1476   SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
   1477   scoped_refptr<SiteInstance> new_instance =
   1478       GetSiteInstanceForNavigation(
   1479           entry.GetURL(),
   1480           entry.site_instance(),
   1481           entry.GetTransitionType(),
   1482           entry.restore_type() != NavigationEntryImpl::RESTORE_NONE,
   1483           entry.IsViewSourceMode());
   1484 
   1485   const NavigationEntry* current_entry =
   1486       delegate_->GetLastCommittedNavigationEntryForRenderManager();
   1487 
   1488   if (new_instance.get() != current_instance) {
   1489     TRACE_EVENT_INSTANT2(
   1490         "navigation",
   1491         "RenderFrameHostManager::UpdateStateForNavigate:New SiteInstance",
   1492         TRACE_EVENT_SCOPE_THREAD,
   1493         "current_instance id", current_instance->GetId(),
   1494         "new_instance id", new_instance->GetId());
   1495 
   1496     // New SiteInstance: create a pending RFH to navigate.
   1497     DCHECK(!cross_navigation_pending_);
   1498 
   1499     // This will possibly create (set to NULL) a Web UI object for the pending
   1500     // page. We'll use this later to give the page special access. This must
   1501     // happen before the new renderer is created below so it will get bindings.
   1502     // It must also happen after the above conditional call to CancelPending(),
   1503     // otherwise CancelPending may clear the pending_web_ui_ and the page will
   1504     // not have its bindings set appropriately.
   1505     SetPendingWebUI(entry);
   1506     CreateRenderFrameHostForNewSiteInstance(
   1507         current_instance, new_instance.get(), frame_tree_node_->IsMainFrame());
   1508     if (!pending_render_frame_host_.get()) {
   1509       return NULL;
   1510     }
   1511 
   1512     // Check if our current RFH is live before we set up a transition.
   1513     if (!render_frame_host_->IsRenderFrameLive()) {
   1514       if (!cross_navigation_pending_) {
   1515         // The current RFH is not live.  There's no reason to sit around with a
   1516         // sad tab or a newly created RFH while we wait for the pending RFH to
   1517         // navigate.  Just switch to the pending RFH now and go back to non
   1518         // cross-navigating (Note that we don't care about on{before}unload
   1519         // handlers if the current RFH isn't live.)
   1520         CommitPending();
   1521         return render_frame_host_.get();
   1522       } else {
   1523         NOTREACHED();
   1524         return render_frame_host_.get();
   1525       }
   1526     }
   1527     // Otherwise, it's safe to treat this as a pending cross-site transition.
   1528 
   1529     // We need to wait until the beforeunload handler has run, unless we are
   1530     // transferring an existing request (in which case it has already run).
   1531     // Suspend the new render view (i.e., don't let it send the cross-site
   1532     // Navigate message) until we hear back from the old renderer's
   1533     // beforeunload handler.  If the handler returns false, we'll have to
   1534     // cancel the request.
   1535     DCHECK(!pending_render_frame_host_->are_navigations_suspended());
   1536     bool is_transfer =
   1537         entry.transferred_global_request_id() != GlobalRequestID();
   1538     if (is_transfer) {
   1539       // We don't need to stop the old renderer or run beforeunload/unload
   1540       // handlers, because those have already been done.
   1541       DCHECK(cross_site_transferring_request_->request_id() ==
   1542                 entry.transferred_global_request_id());
   1543     } else {
   1544       // Also make sure the old render view stops, in case a load is in
   1545       // progress.  (We don't want to do this for transfers, since it will
   1546       // interrupt the transfer with an unexpected DidStopLoading.)
   1547       render_frame_host_->Send(new FrameMsg_Stop(
   1548           render_frame_host_->GetRoutingID()));
   1549       pending_render_frame_host_->SetNavigationsSuspended(true,
   1550                                                           base::TimeTicks());
   1551     }
   1552 
   1553     // We now have a pending RFH.
   1554     DCHECK(!cross_navigation_pending_);
   1555     cross_navigation_pending_ = true;
   1556 
   1557     // Unless we are transferring an existing request, we should now
   1558     // tell the old render view to run its beforeunload handler, since it
   1559     // doesn't otherwise know that the cross-site request is happening.  This
   1560     // will trigger a call to OnBeforeUnloadACK with the reply.
   1561     if (!is_transfer)
   1562       render_frame_host_->DispatchBeforeUnload(true);
   1563 
   1564     return pending_render_frame_host_.get();
   1565   }
   1566 
   1567   // Otherwise the same SiteInstance can be used.  Navigate render_frame_host_.
   1568   DCHECK(!cross_navigation_pending_);
   1569 
   1570   // It's possible to swap out the current RFH and then decide to navigate in it
   1571   // anyway (e.g., a cross-process navigation that redirects back to the
   1572   // original site).  In that case, we have a proxy for the current RFH but
   1573   // haven't deleted it yet.  The new navigation will swap it back in, so we can
   1574   // delete the proxy.
   1575   DeleteRenderFrameProxyHost(new_instance.get());
   1576 
   1577   if (ShouldReuseWebUI(current_entry, &entry)) {
   1578     pending_web_ui_.reset();
   1579     pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
   1580   } else {
   1581     SetPendingWebUI(entry);
   1582 
   1583     // Make sure the new RenderViewHost has the right bindings.
   1584     if (pending_web_ui() &&
   1585         !render_frame_host_->GetProcess()->IsIsolatedGuest()) {
   1586       render_frame_host_->render_view_host()->AllowBindings(
   1587           pending_web_ui()->GetBindings());
   1588     }
   1589   }
   1590 
   1591   if (pending_web_ui() && render_frame_host_->IsRenderFrameLive()) {
   1592     pending_web_ui()->GetController()->RenderViewReused(
   1593         render_frame_host_->render_view_host());
   1594   }
   1595 
   1596   // The renderer can exit view source mode when any error or cancellation
   1597   // happen. We must overwrite to recover the mode.
   1598   if (entry.IsViewSourceMode()) {
   1599     render_frame_host_->render_view_host()->Send(
   1600         new ViewMsg_EnableViewSourceMode(
   1601             render_frame_host_->render_view_host()->GetRoutingID()));
   1602   }
   1603 
   1604   return render_frame_host_.get();
   1605 }
   1606 
   1607 void RenderFrameHostManager::CancelPending() {
   1608   TRACE_EVENT1("navigation", "RenderFrameHostManager::CancelPending",
   1609                "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
   1610   scoped_ptr<RenderFrameHostImpl> pending_render_frame_host =
   1611       pending_render_frame_host_.Pass();
   1612 
   1613   RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
   1614       pending_render_frame_host->render_view_host(),
   1615       render_frame_host_->render_view_host());
   1616 
   1617   // We no longer need to prevent the process from exiting.
   1618   pending_render_frame_host->GetProcess()->RemovePendingView();
   1619 
   1620   // If the SiteInstance for the pending RFH is being used by others, don't
   1621   // delete the RFH, just swap it out and it can be reused at a later point.
   1622   SiteInstanceImpl* site_instance = static_cast<SiteInstanceImpl*>(
   1623       pending_render_frame_host->GetSiteInstance());
   1624   if (site_instance->active_view_count() > 1) {
   1625     // Any currently suspended navigations are no longer needed.
   1626     pending_render_frame_host->CancelSuspendedNavigations();
   1627 
   1628     RenderFrameProxyHost* proxy =
   1629         new RenderFrameProxyHost(site_instance, frame_tree_node_);
   1630     proxy_hosts_[site_instance->GetId()] = proxy;
   1631     pending_render_frame_host->SwapOut(proxy);
   1632     if (frame_tree_node_->IsMainFrame())
   1633       proxy->TakeFrameHostOwnership(pending_render_frame_host.Pass());
   1634   } else {
   1635     // We won't be coming back, so delete this one.
   1636     pending_render_frame_host.reset();
   1637   }
   1638 
   1639   pending_web_ui_.reset();
   1640   pending_and_current_web_ui_.reset();
   1641 }
   1642 
   1643 scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::SetRenderFrameHost(
   1644     scoped_ptr<RenderFrameHostImpl> render_frame_host) {
   1645   // Swap the two.
   1646   scoped_ptr<RenderFrameHostImpl> old_render_frame_host =
   1647       render_frame_host_.Pass();
   1648   render_frame_host_ = render_frame_host.Pass();
   1649 
   1650   if (frame_tree_node_->IsMainFrame()) {
   1651     // Update the count of top-level frames using this SiteInstance.  All
   1652     // subframes are in the same BrowsingInstance as the main frame, so we only
   1653     // count top-level ones.  This makes the value easier for consumers to
   1654     // interpret.
   1655     if (render_frame_host_) {
   1656       static_cast<SiteInstanceImpl*>(render_frame_host_->GetSiteInstance())->
   1657           IncrementRelatedActiveContentsCount();
   1658     }
   1659     if (old_render_frame_host) {
   1660       static_cast<SiteInstanceImpl*>(old_render_frame_host->GetSiteInstance())->
   1661           DecrementRelatedActiveContentsCount();
   1662     }
   1663   }
   1664 
   1665   return old_render_frame_host.Pass();
   1666 }
   1667 
   1668 bool RenderFrameHostManager::IsRVHOnSwappedOutList(
   1669     RenderViewHostImpl* rvh) const {
   1670   RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(
   1671       rvh->GetSiteInstance());
   1672   if (!proxy)
   1673     return false;
   1674   // If there is a proxy without RFH, it is for a subframe in the SiteInstance
   1675   // of |rvh|. Subframes should be ignored in this case.
   1676   if (!proxy->render_frame_host())
   1677     return false;
   1678   return IsOnSwappedOutList(proxy->render_frame_host());
   1679 }
   1680 
   1681 bool RenderFrameHostManager::IsOnSwappedOutList(
   1682     RenderFrameHostImpl* rfh) const {
   1683   if (!rfh->GetSiteInstance())
   1684     return false;
   1685 
   1686   RenderFrameProxyHostMap::const_iterator iter = proxy_hosts_.find(
   1687       rfh->GetSiteInstance()->GetId());
   1688   if (iter == proxy_hosts_.end())
   1689     return false;
   1690 
   1691   return iter->second->render_frame_host() == rfh;
   1692 }
   1693 
   1694 RenderViewHostImpl* RenderFrameHostManager::GetSwappedOutRenderViewHost(
   1695    SiteInstance* instance) const {
   1696   RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
   1697   if (proxy)
   1698     return proxy->GetRenderViewHost();
   1699   return NULL;
   1700 }
   1701 
   1702 RenderFrameProxyHost* RenderFrameHostManager::GetRenderFrameProxyHost(
   1703     SiteInstance* instance) const {
   1704   RenderFrameProxyHostMap::const_iterator iter =
   1705       proxy_hosts_.find(instance->GetId());
   1706   if (iter != proxy_hosts_.end())
   1707     return iter->second;
   1708 
   1709   return NULL;
   1710 }
   1711 
   1712 void RenderFrameHostManager::DeleteRenderFrameProxyHost(
   1713     SiteInstance* instance) {
   1714   RenderFrameProxyHostMap::iterator iter = proxy_hosts_.find(instance->GetId());
   1715   if (iter != proxy_hosts_.end()) {
   1716     delete iter->second;
   1717     proxy_hosts_.erase(iter);
   1718   }
   1719 }
   1720 
   1721 }  // namespace content
   1722