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