render_frame_host_manager.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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
46namespace content {
47
48namespace {
49
50// PlzNavigate
51// Simulates a renderer response to a navigation request when there is no live
52// renderer.
53FrameHostMsg_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
78bool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) {
79  node->render_manager()->pending_delete_hosts_.clear();
80  return true;
81}
82
83RenderFrameHostManager::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
100RenderFrameHostManager::~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
121void 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
145RenderViewHostImpl* RenderFrameHostManager::current_host() const {
146  if (!render_frame_host_)
147    return NULL;
148  return render_frame_host_->render_view_host();
149}
150
151RenderViewHostImpl* 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
157RenderWidgetHostView* 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
165RenderFrameProxyHost* 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
181void 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
199RenderFrameHostImpl* 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
258void 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
269void 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
275bool 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
309void 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
355void 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
419void 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
427void 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
439void 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
476void 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
497void 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
518void 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
554void 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
563void RenderFrameHostManager::ResetProxyHosts() {
564  STLDeleteValues(&proxy_hosts_);
565}
566
567// PlzNavigate
568bool 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
584void 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
613void 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
668void 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
684bool 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
719bool 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
729bool 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
790bool 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
802SiteInstance* 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
856SiteInstance* 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
1025void 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
1055scoped_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
1087int 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
1194int 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
1210bool 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
1239bool 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
1254int 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
1267void 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
1438void 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
1466RenderFrameHostImpl* 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
1607void 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
1643scoped_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
1668bool 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
1681bool 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
1694RenderViewHostImpl* RenderFrameHostManager::GetSwappedOutRenderViewHost(
1695   SiteInstance* instance) const {
1696  RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
1697  if (proxy)
1698    return proxy->GetRenderViewHost();
1699  return NULL;
1700}
1701
1702RenderFrameProxyHost* 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
1712void 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