render_frame_host_manager.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley// Copyright 2013 The Chromium Authors. All rights reserved.
295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley// Use of this source code is governed by a BSD-style license that can be
395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley// found in the LICENSE file.
495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/render_frame_host_manager.h"
695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <utility>
895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/command_line.h"
1095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/debug/trace_event.h"
1195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/logging.h"
1295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/stl_util.h"
1395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/child_process_security_policy_impl.h"
1495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/devtools/render_view_devtools_agent_host.h"
1595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/cross_site_transferring_request.h"
1695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/debug_urls.h"
1795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/interstitial_page_impl.h"
1895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/navigation_controller_impl.h"
1995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/navigation_entry_impl.h"
2095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/navigation_request.h"
2195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/navigation_request_info.h"
2295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/navigator.h"
2395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/render_frame_host_factory.h"
2495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/render_frame_host_impl.h"
2595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/frame_host/render_frame_proxy_host.h"
2695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/renderer_host/render_process_host_impl.h"
2795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/renderer_host/render_view_host_factory.h"
2895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/renderer_host/render_view_host_impl.h"
2995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/site_instance_impl.h"
3095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/webui/web_ui_controller_factory_registry.h"
3195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/browser/webui/web_ui_impl.h"
3295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/common/view_messages.h"
3395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/browser/content_browser_client.h"
3495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/browser/notification_service.h"
3595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/browser/notification_types.h"
3695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/browser/render_widget_host_iterator.h"
3795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/browser/render_widget_host_view.h"
3895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/browser/user_metrics.h"
3995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/browser/web_ui_controller.h"
4095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/common/content_switches.h"
4195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/common/url_constants.h"
4295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
4395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleynamespace content {
4495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
4595c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyRenderFrameHostManager::PendingNavigationParams::PendingNavigationParams(
4695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const GlobalRequestID& global_request_id,
4795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
4895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const std::vector<GURL>& transfer_url_chain,
4995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    Referrer referrer,
5095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    PageTransition page_transition,
5195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    int render_frame_id,
5295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    bool should_replace_current_entry)
5395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    : global_request_id(global_request_id),
5495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      cross_site_transferring_request(cross_site_transferring_request.Pass()),
5595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      transfer_url_chain(transfer_url_chain),
5695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      referrer(referrer),
5795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      page_transition(page_transition),
5895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      render_frame_id(render_frame_id),
5995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      should_replace_current_entry(should_replace_current_entry) {
6095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
6195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
6295c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyRenderFrameHostManager::PendingNavigationParams::~PendingNavigationParams() {}
6395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
6495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleybool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) {
6595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  node->render_manager()->pending_delete_hosts_.clear();
6695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return true;
6795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
6895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
6995c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyRenderFrameHostManager::RenderFrameHostManager(
7095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    FrameTreeNode* frame_tree_node,
7195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    RenderFrameHostDelegate* render_frame_delegate,
7295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    RenderViewHostDelegate* render_view_delegate,
7395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    RenderWidgetHostDelegate* render_widget_delegate,
7495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    Delegate* delegate)
7595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    : frame_tree_node_(frame_tree_node),
7695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      delegate_(delegate),
7795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      cross_navigation_pending_(false),
7895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      render_frame_delegate_(render_frame_delegate),
7995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      render_view_delegate_(render_view_delegate),
8095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      render_widget_delegate_(render_widget_delegate),
8195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      interstitial_page_(NULL),
8295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      weak_factory_(this) {
8395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  DCHECK(frame_tree_node_);
8495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
8595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
8695c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyRenderFrameHostManager::~RenderFrameHostManager() {
8795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (pending_render_frame_host_)
8895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    CancelPending();
8995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
9095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // We should always have a current RenderFrameHost except in some tests.
9195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  SetRenderFrameHost(scoped_ptr<RenderFrameHostImpl>());
9295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
9395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Delete any swapped out RenderFrameHosts.
9495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  STLDeleteValues(&proxy_hosts_);
9595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
9695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
9795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RenderFrameHostManager::Init(BrowserContext* browser_context,
9895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                  SiteInstance* site_instance,
9995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                  int view_routing_id,
10095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                  int frame_routing_id) {
10195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Create a RenderViewHost and RenderFrameHost, once we have an instance.  It
10295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // is important to immediately give this SiteInstance to a RenderViewHost so
10395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // that the SiteInstance is ref counted.
10495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!site_instance)
10595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    site_instance = SiteInstance::Create(browser_context);
10695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
10795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  SetRenderFrameHost(CreateRenderFrameHost(site_instance,
10895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                           view_routing_id,
10995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                           frame_routing_id,
11095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                           false,
11195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                           delegate_->IsHidden()));
11295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Keep track of renderer processes as they start to shut down or are
11495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // crashed/killed.
11595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
11695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                 NotificationService::AllSources());
11795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSING,
11895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                 NotificationService::AllSources());
11995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
12095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
12195c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyRenderViewHostImpl* RenderFrameHostManager::current_host() const {
12295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!render_frame_host_)
12395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
12495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return render_frame_host_->render_view_host();
12595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
12695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
12795c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyRenderViewHostImpl* RenderFrameHostManager::pending_render_view_host() const {
12895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!pending_render_frame_host_)
12995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
13095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return pending_render_frame_host_->render_view_host();
13195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
13295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
13395c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyRenderWidgetHostView* RenderFrameHostManager::GetRenderWidgetHostView() const {
13495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (interstitial_page_)
13595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return interstitial_page_->GetView();
13695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!render_frame_host_)
13795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
13895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return render_frame_host_->render_view_host()->GetView();
13995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
14095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
14195c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyRenderFrameProxyHost* RenderFrameHostManager::GetProxyToParent() {
14295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (frame_tree_node_->IsMainFrame())
14395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
14495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
14595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  RenderFrameProxyHostMap::iterator iter =
14695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      proxy_hosts_.find(frame_tree_node_->parent()
14795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                            ->render_manager()
14895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                            ->current_frame_host()
14995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                            ->GetSiteInstance()
15095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                            ->GetId());
15195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (iter == proxy_hosts_.end())
15295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
15395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
15495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return iter->second;
15595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
15695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
15795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RenderFrameHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
15895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pending_web_ui_.reset(
15995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      delegate_->CreateWebUIForRenderManager(entry.GetURL()));
16095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pending_and_current_web_ui_.reset();
16195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
16295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // If we have assigned (zero or more) bindings to this NavigationEntry in the
16395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // past, make sure we're not granting it different bindings than it had
16495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // before.  If so, note it and don't give it any bindings, to avoid a
16595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // potential privilege escalation.
16695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (pending_web_ui_.get() &&
16795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      entry.bindings() != NavigationEntryImpl::kInvalidBindings &&
16895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      pending_web_ui_->GetBindings() != entry.bindings()) {
16995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    RecordAction(
17095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
17195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    pending_web_ui_.reset();
17295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
17395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
17495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
17595c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyRenderFrameHostImpl* RenderFrameHostManager::Navigate(
17695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const NavigationEntryImpl& entry) {
17795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  TRACE_EVENT0("browser", "RenderFrameHostManager:Navigate");
17895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Create a pending RenderFrameHost to use for the navigation.
17995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  RenderFrameHostImpl* dest_render_frame_host = UpdateStateForNavigate(entry);
18095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!dest_render_frame_host)
18195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;  // We weren't able to create a pending render frame host.
18295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
18395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // If the current render_frame_host_ isn't live, we should create it so
18495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // that we don't show a sad tab while the dest_render_frame_host fetches
18595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // its first page.  (Bug 1145340)
18695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (dest_render_frame_host != render_frame_host_ &&
18795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      !render_frame_host_->render_view_host()->IsRenderViewLive()) {
18895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // Note: we don't call InitRenderView here because we are navigating away
18995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // soon anyway, and we don't have the NavigationEntry for this host.
19095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    delegate_->CreateRenderViewForRenderManager(
19195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        render_frame_host_->render_view_host(), MSG_ROUTING_NONE,
19295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        MSG_ROUTING_NONE, frame_tree_node_->IsMainFrame());
19395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
19495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // If the renderer crashed, then try to create a new one to satisfy this
19695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // navigation request.
19795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!dest_render_frame_host->render_view_host()->IsRenderViewLive()) {
19895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // Recreate the opener chain.
19995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
20095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        dest_render_frame_host->GetSiteInstance());
20195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!InitRenderView(dest_render_frame_host->render_view_host(),
20295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                        opener_route_id,
20395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                        MSG_ROUTING_NONE,
20495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                        frame_tree_node_->IsMainFrame()))
20595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return NULL;
20695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // Now that we've created a new renderer, be sure to hide it if it isn't
20895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // our primary one.  Otherwise, we might crash if we try to call Show()
20995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // on it later.
21095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (dest_render_frame_host != render_frame_host_ &&
21195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        dest_render_frame_host->render_view_host()->GetView()) {
21295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      dest_render_frame_host->render_view_host()->GetView()->Hide();
21395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
21495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // Notify here as we won't be calling CommitPending (which does the
21595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // notify).
21695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      delegate_->NotifySwappedFromRenderManager(
21795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          NULL, render_frame_host_.get(), frame_tree_node_->IsMainFrame());
21895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
21995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
22095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // If entry includes the request ID of a request that is being transferred,
22295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // the destination render frame will take ownership, so release ownership of
22395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // the request.
22495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (pending_nav_params_ &&
22595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      pending_nav_params_->global_request_id ==
22695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          entry.transferred_global_request_id()) {
22795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    pending_nav_params_->cross_site_transferring_request->ReleaseRequest();
22895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
22995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return dest_render_frame_host;
23195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
23295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RenderFrameHostManager::Stop() {
23495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  render_frame_host_->render_view_host()->Stop();
23595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // If we are cross-navigating, we should stop the pending renderers.  This
23795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // will lead to a DidFailProvisionalLoad, which will properly destroy them.
23895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (cross_navigation_pending_) {
23995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    pending_render_frame_host_->render_view_host()->Send(new ViewMsg_Stop(
24095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        pending_render_frame_host_->render_view_host()->GetRoutingID()));
24195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
24295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
24395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RenderFrameHostManager::SetIsLoading(bool is_loading) {
24595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  render_frame_host_->render_view_host()->SetIsLoading(is_loading);
24695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (pending_render_frame_host_)
24795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    pending_render_frame_host_->render_view_host()->SetIsLoading(is_loading);
24895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
24995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleybool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
25195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!cross_navigation_pending_)
25295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return true;
25395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // We should always have a pending RFH when there's a cross-process navigation
25595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // in progress.  Sanity check this for http://crbug.com/276333.
25695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CHECK(pending_render_frame_host_);
25795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // If the tab becomes unresponsive during {before}unload while doing a
25995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // cross-site navigation, proceed with the navigation.  (This assumes that
26095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // the pending RenderFrameHost is still responsive.)
26195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (render_frame_host_->render_view_host()->IsWaitingForUnloadACK()) {
26295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // The request has been started and paused while we're waiting for the
26395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // unload handler to finish.  We'll pretend that it did.  The pending
26495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // renderer will then be swapped in as part of the usual DidNavigate logic.
26595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // (If the unload handler later finishes, this call will be ignored because
26695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // the pending_nav_params_ state will already be cleaned up.)
26795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    current_host()->OnSwappedOut(true);
26895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else if (render_frame_host_->render_view_host()->
26995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                 is_waiting_for_beforeunload_ack()) {
27095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // Haven't gotten around to starting the request, because we're still
27195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // waiting for the beforeunload handler to finish.  We'll pretend that it
27295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // did finish, to let the navigation proceed.  Note that there's a danger
27395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // that the beforeunload handler will later finish and possibly return
27495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // false (meaning the navigation should not proceed), but we'll ignore it
27595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // in this case because it took too long.
27695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (pending_render_frame_host_->are_navigations_suspended()) {
27795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      pending_render_frame_host_->SetNavigationsSuspended(
27895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          false, base::TimeTicks::Now());
27995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
28095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
28195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return false;
28295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
28395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
28495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RenderFrameHostManager::OnBeforeUnloadACK(
28595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    bool for_cross_site_transition,
28695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    bool proceed,
28795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const base::TimeTicks& proceed_time) {
28895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (for_cross_site_transition) {
28995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // Ignore if we're not in a cross-site navigation.
29095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!cross_navigation_pending_)
29195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return;
29295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
29395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (proceed) {
29495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // Ok to unload the current page, so proceed with the cross-site
29595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // navigation.  Note that if navigations are not currently suspended, it
29695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // might be because the renderer was deemed unresponsive and this call was
29795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // already made by ShouldCloseTabOnUnresponsiveRenderer.  In that case, it
29895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // is ok to do nothing here.
29995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (pending_render_frame_host_ &&
30095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          pending_render_frame_host_->are_navigations_suspended()) {
30195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        pending_render_frame_host_->SetNavigationsSuspended(false,
30295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                                            proceed_time);
30395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      }
30495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
30595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // Current page says to cancel.
30695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      CancelPending();
30795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      cross_navigation_pending_ = false;
30895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
30995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else {
31095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // Non-cross site transition means closing the entire tab.
31195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    bool proceed_to_fire_unload;
31295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
31395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                                  &proceed_to_fire_unload);
31495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
31595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (proceed_to_fire_unload) {
31695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // If we're about to close the tab and there's a pending RFH, cancel it.
31795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // Otherwise, if the navigation in the pending RFH completes before the
31895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // close in the current RFH, we'll lose the tab close.
31995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (pending_render_frame_host_) {
32095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        CancelPending();
32195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        cross_navigation_pending_ = false;
32295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      }
32395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
32495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      // This is not a cross-site navigation, the tab is being closed.
32595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      render_frame_host_->render_view_host()->ClosePage();
32695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
32795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
32895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
32995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
33095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RenderFrameHostManager::OnCrossSiteResponse(
33195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    RenderFrameHostImpl* pending_render_frame_host,
33295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const GlobalRequestID& global_request_id,
33395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
33495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const std::vector<GURL>& transfer_url_chain,
33595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const Referrer& referrer,
33695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    PageTransition page_transition,
33795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    bool should_replace_current_entry) {
33895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // This should be called either when the pending RFH is ready to commit or
33995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // when we realize that the current RFH's request requires a transfer.
34095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  DCHECK(pending_render_frame_host == pending_render_frame_host_ ||
34195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley         pending_render_frame_host == render_frame_host_);
34295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
34395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // TODO(creis): Eventually we will want to check all navigation responses
34495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // here, but currently we pass information for a transfer if
34595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // ShouldSwapProcessesForRedirect returned true in the network stack.
34695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // In that case, we should set up a transfer after the unload handler runs.
34795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // If |cross_site_transferring_request| is NULL, we will just run the unload
34895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // handler and resume.
34995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pending_nav_params_.reset(new PendingNavigationParams(
35095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      global_request_id, cross_site_transferring_request.Pass(),
35195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      transfer_url_chain, referrer, page_transition,
35295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      pending_render_frame_host->GetRoutingID(),
35395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      should_replace_current_entry));
35495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
35595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Run the unload handler of the current page.
35695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  SwapOutOldPage();
35795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
35895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
35995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RenderFrameHostManager::OnDeferredAfterResponseStarted(
36095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const GlobalRequestID& global_request_id,
36195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    RenderFrameHostImpl* pending_render_frame_host) {
36295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  DCHECK(!response_started_id_.get());
36395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
36495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  response_started_id_.reset(new GlobalRequestID(global_request_id));
36595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
36695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
36795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RenderFrameHostManager::ResumeResponseDeferredAtStart() {
36895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  DCHECK(response_started_id_.get());
36995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
37095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  RenderProcessHostImpl* process =
37195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      static_cast<RenderProcessHostImpl*>(render_frame_host_->GetProcess());
37295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  process->ResumeResponseDeferredAtStart(*response_started_id_);
37395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
37495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  render_frame_host_->ClearPendingTransitionRequestData();
37595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
37695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  response_started_id_.reset();
37795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
37895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
37995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RenderFrameHostManager::SwappedOut(
38095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    RenderFrameHostImpl* render_frame_host) {
38195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Make sure this is from our current RFH, and that we have a pending
38295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // navigation from OnCrossSiteResponse.  (There may be no pending navigation
38395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // for data URLs that don't make network requests, for example.)   If not,
38495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // just return early and ignore.
38595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (render_frame_host != render_frame_host_ || !pending_nav_params_.get()) {
38695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    pending_nav_params_.reset();
38795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return;
38895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
38995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
39095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Now that the unload handler has run, we need to either initiate the
39195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // pending transfer (if there is one) or resume the paused response (if not).
39295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // TODO(creis): The blank swapped out page is visible during this time, but
39395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // we can shorten this by delivering the response directly, rather than
39495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // forcing an identical request to be made.
395  if (pending_nav_params_->cross_site_transferring_request) {
396    // Sanity check that the params are for the correct frame and process.
397    // These should match the RenderFrameHost that made the request.
398    // If it started as a cross-process navigation via OpenURL, this is the
399    // pending one.  If it wasn't cross-process until the transfer, this is the
400    // current one.
401    int render_frame_id = pending_render_frame_host_ ?
402        pending_render_frame_host_->GetRoutingID() :
403        render_frame_host_->GetRoutingID();
404    DCHECK_EQ(render_frame_id, pending_nav_params_->render_frame_id);
405    int process_id = pending_render_frame_host_ ?
406        pending_render_frame_host_->GetProcess()->GetID() :
407        render_frame_host_->GetProcess()->GetID();
408    DCHECK_EQ(process_id, pending_nav_params_->global_request_id.child_id);
409
410    // Treat the last URL in the chain as the destination and the remainder as
411    // the redirect chain.
412    CHECK(pending_nav_params_->transfer_url_chain.size());
413    GURL transfer_url = pending_nav_params_->transfer_url_chain.back();
414    pending_nav_params_->transfer_url_chain.pop_back();
415
416    // We don't know whether the original request had |user_action| set to true.
417    // However, since we force the navigation to be in the current tab, it
418    // doesn't matter.
419    render_frame_host->frame_tree_node()->navigator()->RequestTransferURL(
420        render_frame_host,
421        transfer_url,
422        pending_nav_params_->transfer_url_chain,
423        pending_nav_params_->referrer,
424        pending_nav_params_->page_transition,
425        CURRENT_TAB,
426        pending_nav_params_->global_request_id,
427        pending_nav_params_->should_replace_current_entry,
428        true);
429  } else if (pending_render_frame_host_) {
430    RenderProcessHostImpl* pending_process =
431        static_cast<RenderProcessHostImpl*>(
432            pending_render_frame_host_->GetProcess());
433    pending_process->ResumeDeferredNavigation(
434        pending_nav_params_->global_request_id);
435  }
436  pending_nav_params_.reset();
437}
438
439void RenderFrameHostManager::DidNavigateFrame(
440    RenderFrameHostImpl* render_frame_host) {
441  if (!cross_navigation_pending_) {
442    DCHECK(!pending_render_frame_host_);
443
444    // We should only hear this from our current renderer.
445    DCHECK_EQ(render_frame_host_, render_frame_host);
446
447    // Even when there is no pending RVH, there may be a pending Web UI.
448    if (pending_web_ui())
449      CommitPending();
450    return;
451  }
452
453  if (render_frame_host == pending_render_frame_host_) {
454    // The pending cross-site navigation completed, so show the renderer.
455    // If it committed without sending network requests (e.g., data URLs),
456    // then we still need to swap out the old RFH first and run its unload
457    // handler, only if it hasn't happened yet.  OK for that to happen in the
458    // background.
459    if (pending_render_frame_host_->HasPendingCrossSiteRequest() &&
460        pending_render_frame_host_->render_view_host()->rvh_state() ==
461            RenderViewHostImpl::STATE_DEFAULT) {
462      SwapOutOldPage();
463    }
464
465    CommitPending();
466    cross_navigation_pending_ = false;
467  } else if (render_frame_host == render_frame_host_) {
468    // A navigation in the original page has taken place.  Cancel the pending
469    // one.
470    CancelPending();
471    cross_navigation_pending_ = false;
472  } else {
473    // No one else should be sending us DidNavigate in this state.
474    DCHECK(false);
475  }
476}
477
478// TODO(creis): Take in RenderFrameHost instead, since frames can have openers.
479void RenderFrameHostManager::DidDisownOpener(RenderViewHost* render_view_host) {
480  // Notify all swapped out hosts, including the pending RVH.
481  for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
482       iter != proxy_hosts_.end();
483       ++iter) {
484    DCHECK_NE(iter->second->GetSiteInstance(),
485              current_frame_host()->GetSiteInstance());
486    iter->second->GetRenderViewHost()->DisownOpener();
487  }
488}
489
490void RenderFrameHostManager::RendererProcessClosing(
491    RenderProcessHost* render_process_host) {
492  // Remove any swapped out RVHs from this process, so that we don't try to
493  // swap them back in while the process is exiting.  Start by finding them,
494  // since there could be more than one.
495  std::list<int> ids_to_remove;
496  for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
497       iter != proxy_hosts_.end();
498       ++iter) {
499    if (iter->second->GetProcess() == render_process_host)
500      ids_to_remove.push_back(iter->first);
501  }
502
503  // Now delete them.
504  while (!ids_to_remove.empty()) {
505    delete proxy_hosts_[ids_to_remove.back()];
506    proxy_hosts_.erase(ids_to_remove.back());
507    ids_to_remove.pop_back();
508  }
509}
510
511void RenderFrameHostManager::SwapOutOldPage() {
512  // Should only see this while we have a pending renderer or transfer.
513  CHECK(cross_navigation_pending_ || pending_nav_params_.get());
514
515  // Tell the renderer to suppress any further modal dialogs so that we can swap
516  // it out.  This must be done before canceling any current dialog, in case
517  // there is a loop creating additional dialogs.
518  // TODO(creis): Handle modal dialogs in subframe processes.
519  render_frame_host_->render_view_host()->SuppressDialogsUntilSwapOut();
520
521  // Now close any modal dialogs that would prevent us from swapping out.  This
522  // must be done separately from SwapOut, so that the PageGroupLoadDeferrer is
523  // no longer on the stack when we send the SwapOut message.
524  delegate_->CancelModalDialogsForRenderManager();
525
526  // Create the RenderFrameProxyHost that will replace the
527  // RenderFrameHost which is swapping out. If one exists, ensure it is deleted
528  // from the map and not leaked.
529  DeleteRenderFrameProxyHost(render_frame_host_->GetSiteInstance());
530
531  RenderFrameProxyHost* proxy = new RenderFrameProxyHost(
532      render_frame_host_->GetSiteInstance(), frame_tree_node_);
533  std::pair<RenderFrameProxyHostMap::iterator, bool> result =
534      proxy_hosts_.insert(std::make_pair(
535          render_frame_host_->GetSiteInstance()->GetId(), proxy));
536  CHECK(result.second) << "Inserting a duplicate item.";
537
538  // Tell the old frame it is being swapped out.  This will fire the unload
539  // handler in the background (without firing the beforeunload handler a second
540  // time).  When the navigation completes, we will send a message to the
541  // ResourceDispatcherHost, allowing the pending RVH's response to resume.
542  render_frame_host_->SwapOut(proxy);
543
544  // ResourceDispatcherHost has told us to run the onunload handler, which
545  // means it is not a download or unsafe page, and we are going to perform the
546  // navigation.  Thus, we no longer need to remember that the RenderFrameHost
547  // is part of a pending cross-site request.
548  if (pending_render_frame_host_) {
549    pending_render_frame_host_->SetHasPendingCrossSiteRequest(false);
550  }
551}
552
553void RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance(
554    int32 site_instance_id,
555    RenderFrameHostImpl* rfh) {
556  RFHPendingDeleteMap::iterator iter =
557      pending_delete_hosts_.find(site_instance_id);
558  if (iter != pending_delete_hosts_.end() && iter->second.get() == rfh)
559    pending_delete_hosts_.erase(site_instance_id);
560}
561
562void RenderFrameHostManager::ResetProxyHosts() {
563  STLDeleteValues(&proxy_hosts_);
564}
565
566void RenderFrameHostManager::OnBeginNavigation(
567    const FrameHostMsg_BeginNavigation_Params& params) {
568  // TODO(clamy): Check if navigations are blocked and if so, return
569  // immediately.
570  NavigationRequestInfo info(params);
571
572  info.first_party_for_cookies = frame_tree_node_->IsMainFrame() ?
573      params.url : frame_tree_node_->frame_tree()->root()->current_url();
574  info.is_main_frame = frame_tree_node_->IsMainFrame();
575  info.parent_is_main_frame = !frame_tree_node_->parent() ?
576      false : frame_tree_node_->parent()->IsMainFrame();
577  info.is_showing = GetRenderWidgetHostView()->IsShowing();
578
579  navigation_request_.reset(
580      new NavigationRequest(info, frame_tree_node_->frame_tree_node_id()));
581  navigation_request_->BeginNavigation(params.request_body);
582  // TODO(clamy): If we have no live RenderFrameHost to handle the request (eg
583  // cross-site navigation) spawn one speculatively here and keep track of it.
584}
585
586void RenderFrameHostManager::Observe(
587    int type,
588    const NotificationSource& source,
589    const NotificationDetails& details) {
590  switch (type) {
591    case NOTIFICATION_RENDERER_PROCESS_CLOSED:
592    case NOTIFICATION_RENDERER_PROCESS_CLOSING:
593      RendererProcessClosing(
594          Source<RenderProcessHost>(source).ptr());
595      break;
596
597    default:
598      NOTREACHED();
599  }
600}
601
602bool RenderFrameHostManager::ClearProxiesInSiteInstance(
603    int32 site_instance_id,
604    FrameTreeNode* node) {
605  RenderFrameProxyHostMap::iterator iter =
606      node->render_manager()->proxy_hosts_.find(site_instance_id);
607  if (iter != node->render_manager()->proxy_hosts_.end()) {
608    RenderFrameProxyHost* proxy = iter->second;
609    // If the RVH is pending swap out, it needs to switch state to
610    // pending shutdown. Otherwise it is deleted.
611    if (proxy->GetRenderViewHost()->rvh_state() ==
612        RenderViewHostImpl::STATE_PENDING_SWAP_OUT) {
613      scoped_ptr<RenderFrameHostImpl> swapped_out_rfh =
614          proxy->PassFrameHostOwnership();
615
616      swapped_out_rfh->SetPendingShutdown(base::Bind(
617          &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
618          node->render_manager()->weak_factory_.GetWeakPtr(),
619          site_instance_id,
620          swapped_out_rfh.get()));
621      RFHPendingDeleteMap::iterator pending_delete_iter =
622          node->render_manager()->pending_delete_hosts_.find(site_instance_id);
623      if (pending_delete_iter ==
624              node->render_manager()->pending_delete_hosts_.end() ||
625          pending_delete_iter->second.get() != swapped_out_rfh) {
626        node->render_manager()->pending_delete_hosts_[site_instance_id] =
627            linked_ptr<RenderFrameHostImpl>(swapped_out_rfh.release());
628      }
629    }
630    delete proxy;
631    node->render_manager()->proxy_hosts_.erase(site_instance_id);
632  }
633
634  return true;
635}
636
637bool RenderFrameHostManager::ShouldTransitionCrossSite() {
638  // False in the single-process mode, as it makes RVHs to accumulate
639  // in swapped_out_hosts_.
640  // True if we are using process-per-site-instance (default) or
641  // process-per-site (kProcessPerSite).
642  return
643      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
644      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab);
645}
646
647bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
648    const GURL& current_effective_url,
649    bool current_is_view_source_mode,
650    SiteInstance* new_site_instance,
651    const GURL& new_effective_url,
652    bool new_is_view_source_mode) const {
653  // If new_entry already has a SiteInstance, assume it is correct.  We only
654  // need to force a swap if it is in a different BrowsingInstance.
655  if (new_site_instance) {
656    return !new_site_instance->IsRelatedSiteInstance(
657        render_frame_host_->GetSiteInstance());
658  }
659
660  // Check for reasons to swap processes even if we are in a process model that
661  // doesn't usually swap (e.g., process-per-tab).  Any time we return true,
662  // the new_entry will be rendered in a new SiteInstance AND BrowsingInstance.
663  BrowserContext* browser_context =
664      delegate_->GetControllerForRenderManager().GetBrowserContext();
665
666  // Don't force a new BrowsingInstance for debug URLs that are handled in the
667  // renderer process, like javascript: or chrome://crash.
668  if (IsRendererDebugURL(new_effective_url))
669    return false;
670
671  // For security, we should transition between processes when one is a Web UI
672  // page and one isn't.
673  if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
674          browser_context, current_effective_url)) {
675    // If so, force a swap if destination is not an acceptable URL for Web UI.
676    // Here, data URLs are never allowed.
677    if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
678            browser_context, new_effective_url)) {
679      return true;
680    }
681  } else {
682    // Force a swap if it's a Web UI URL.
683    if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
684            browser_context, new_effective_url)) {
685      return true;
686    }
687  }
688
689  // Check with the content client as well.  Important to pass
690  // current_effective_url here, which uses the SiteInstance's site if there is
691  // no current_entry.
692  if (GetContentClient()->browser()->ShouldSwapBrowsingInstancesForNavigation(
693          render_frame_host_->GetSiteInstance(),
694          current_effective_url, new_effective_url)) {
695    return true;
696  }
697
698  // We can't switch a RenderView between view source and non-view source mode
699  // without screwing up the session history sometimes (when navigating between
700  // "view-source:http://foo.com/" and "http://foo.com/", Blink doesn't treat
701  // it as a new navigation). So require a BrowsingInstance switch.
702  if (current_is_view_source_mode != new_is_view_source_mode)
703    return true;
704
705  return false;
706}
707
708bool RenderFrameHostManager::ShouldReuseWebUI(
709    const NavigationEntry* current_entry,
710    const NavigationEntryImpl* new_entry) const {
711  NavigationControllerImpl& controller =
712      delegate_->GetControllerForRenderManager();
713  return current_entry && web_ui_.get() &&
714      (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
715          controller.GetBrowserContext(), current_entry->GetURL()) ==
716       WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
717          controller.GetBrowserContext(), new_entry->GetURL()));
718}
719
720SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
721    const GURL& dest_url,
722    SiteInstance* dest_instance,
723    PageTransition dest_transition,
724    bool dest_is_restore,
725    bool dest_is_view_source_mode,
726    SiteInstance* current_instance,
727    bool force_browsing_instance_swap) {
728  NavigationControllerImpl& controller =
729      delegate_->GetControllerForRenderManager();
730  BrowserContext* browser_context = controller.GetBrowserContext();
731
732  // If the entry has an instance already we should use it.
733  if (dest_instance) {
734    // If we are forcing a swap, this should be in a different BrowsingInstance.
735    if (force_browsing_instance_swap) {
736      CHECK(!dest_instance->IsRelatedSiteInstance(
737                render_frame_host_->GetSiteInstance()));
738    }
739    return dest_instance;
740  }
741
742  // If a swap is required, we need to force the SiteInstance AND
743  // BrowsingInstance to be different ones, using CreateForURL.
744  if (force_browsing_instance_swap)
745    return SiteInstance::CreateForURL(browser_context, dest_url);
746
747  // (UGLY) HEURISTIC, process-per-site only:
748  //
749  // If this navigation is generated, then it probably corresponds to a search
750  // query.  Given that search results typically lead to users navigating to
751  // other sites, we don't really want to use the search engine hostname to
752  // determine the site instance for this navigation.
753  //
754  // NOTE: This can be removed once we have a way to transition between
755  //       RenderViews in response to a link click.
756  //
757  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) &&
758      PageTransitionCoreTypeIs(dest_transition, PAGE_TRANSITION_GENERATED)) {
759    return current_instance;
760  }
761
762  SiteInstanceImpl* current_site_instance =
763      static_cast<SiteInstanceImpl*>(current_instance);
764
765  // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it
766  // for this entry.  We won't commit the SiteInstance to this site until the
767  // navigation commits (in DidNavigate), unless the navigation entry was
768  // restored or it's a Web UI as described below.
769  if (!current_site_instance->HasSite()) {
770    // If we've already created a SiteInstance for our destination, we don't
771    // want to use this unused SiteInstance; use the existing one.  (We don't
772    // do this check if the current_instance has a site, because for now, we
773    // want to compare against the current URL and not the SiteInstance's site.
774    // In this case, there is no current URL, so comparing against the site is
775    // ok.  See additional comments below.)
776    //
777    // Also, if the URL should use process-per-site mode and there is an
778    // existing process for the site, we should use it.  We can call
779    // GetRelatedSiteInstance() for this, which will eagerly set the site and
780    // thus use the correct process.
781    bool use_process_per_site =
782        RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
783        RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
784    if (current_site_instance->HasRelatedSiteInstance(dest_url) ||
785        use_process_per_site) {
786      return current_site_instance->GetRelatedSiteInstance(dest_url);
787    }
788
789    // For extensions, Web UI URLs (such as the new tab page), and apps we do
790    // not want to use the current_instance if it has no site, since it will
791    // have a RenderProcessHost of PRIV_NORMAL.  Create a new SiteInstance for
792    // this URL instead (with the correct process type).
793    if (current_site_instance->HasWrongProcessForURL(dest_url))
794      return current_site_instance->GetRelatedSiteInstance(dest_url);
795
796    // View-source URLs must use a new SiteInstance and BrowsingInstance.
797    // TODO(nasko): This is the same condition as later in the function. This
798    // should be taken into account when refactoring this method as part of
799    // http://crbug.com/123007.
800    if (dest_is_view_source_mode)
801      return SiteInstance::CreateForURL(browser_context, dest_url);
802
803    // If we are navigating from a blank SiteInstance to a WebUI, make sure we
804    // create a new SiteInstance.
805    if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
806            browser_context, dest_url)) {
807        return SiteInstance::CreateForURL(browser_context, dest_url);
808    }
809
810    // Normally the "site" on the SiteInstance is set lazily when the load
811    // actually commits. This is to support better process sharing in case
812    // the site redirects to some other site: we want to use the destination
813    // site in the site instance.
814    //
815    // In the case of session restore, as it loads all the pages immediately
816    // we need to set the site first, otherwise after a restore none of the
817    // pages would share renderers in process-per-site.
818    //
819    // The embedder can request some urls never to be assigned to SiteInstance
820    // through the ShouldAssignSiteForURL() content client method, so that
821    // renderers created for particular chrome urls (e.g. the chrome-native://
822    // scheme) can be reused for subsequent navigations in the same WebContents.
823    // See http://crbug.com/386542.
824    if (dest_is_restore &&
825        GetContentClient()->browser()->ShouldAssignSiteForURL(dest_url)) {
826      current_site_instance->SetSite(dest_url);
827    }
828
829    return current_site_instance;
830  }
831
832  // Otherwise, only create a new SiteInstance for a cross-site navigation.
833
834  // TODO(creis): Once we intercept links and script-based navigations, we
835  // will be able to enforce that all entries in a SiteInstance actually have
836  // the same site, and it will be safe to compare the URL against the
837  // SiteInstance's site, as follows:
838  // const GURL& current_url = current_instance->site();
839  // For now, though, we're in a hybrid model where you only switch
840  // SiteInstances if you type in a cross-site URL.  This means we have to
841  // compare the entry's URL to the last committed entry's URL.
842  NavigationEntry* current_entry = controller.GetLastCommittedEntry();
843  if (interstitial_page_) {
844    // The interstitial is currently the last committed entry, but we want to
845    // compare against the last non-interstitial entry.
846    current_entry = controller.GetEntryAtOffset(-1);
847  }
848  // If there is no last non-interstitial entry (and current_instance already
849  // has a site), then we must have been opened from another tab.  We want
850  // to compare against the URL of the page that opened us, but we can't
851  // get to it directly.  The best we can do is check against the site of
852  // the SiteInstance.  This will be correct when we intercept links and
853  // script-based navigations, but for now, it could place some pages in a
854  // new process unnecessarily.  We should only hit this case if a page tries
855  // to open a new tab to an interstitial-inducing URL, and then navigates
856  // the page to a different same-site URL.  (This seems very unlikely in
857  // practice.)
858  const GURL& current_url = (current_entry) ? current_entry->GetURL() :
859      current_instance->GetSiteURL();
860
861  // View-source URLs must use a new SiteInstance and BrowsingInstance.
862  // We don't need a swap when going from view-source to a debug URL like
863  // chrome://crash, however.
864  // TODO(creis): Refactor this method so this duplicated code isn't needed.
865  // See http://crbug.com/123007.
866  if (current_entry &&
867      current_entry->IsViewSourceMode() != dest_is_view_source_mode &&
868      !IsRendererDebugURL(dest_url)) {
869    return SiteInstance::CreateForURL(browser_context, dest_url);
870  }
871
872  // Use the current SiteInstance for same site navigations, as long as the
873  // process type is correct.  (The URL may have been installed as an app since
874  // the last time we visited it.)
875  if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
876      !current_site_instance->HasWrongProcessForURL(dest_url)) {
877    return current_instance;
878  }
879
880  // Start the new renderer in a new SiteInstance, but in the current
881  // BrowsingInstance.  It is important to immediately give this new
882  // SiteInstance to a RenderViewHost (if it is different than our current
883  // SiteInstance), so that it is ref counted.  This will happen in
884  // CreateRenderView.
885  return current_instance->GetRelatedSiteInstance(dest_url);
886}
887
888scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
889    SiteInstance* site_instance,
890    int view_routing_id,
891    int frame_routing_id,
892    bool swapped_out,
893    bool hidden) {
894  if (frame_routing_id == MSG_ROUTING_NONE)
895    frame_routing_id = site_instance->GetProcess()->GetNextRoutingID();
896
897  // Create a RVH for main frames, or find the existing one for subframes.
898  FrameTree* frame_tree = frame_tree_node_->frame_tree();
899  RenderViewHostImpl* render_view_host = NULL;
900  if (frame_tree_node_->IsMainFrame()) {
901    render_view_host = frame_tree->CreateRenderViewHost(
902        site_instance, view_routing_id, frame_routing_id, swapped_out, hidden);
903  } else {
904    render_view_host = frame_tree->GetRenderViewHost(site_instance);
905
906    CHECK(render_view_host);
907  }
908
909  // TODO(creis): Pass hidden to RFH.
910  scoped_ptr<RenderFrameHostImpl> render_frame_host =
911      make_scoped_ptr(RenderFrameHostFactory::Create(render_view_host,
912                                                     render_frame_delegate_,
913                                                     frame_tree,
914                                                     frame_tree_node_,
915                                                     frame_routing_id,
916                                                     swapped_out).release());
917  return render_frame_host.Pass();
918}
919
920int RenderFrameHostManager::CreateRenderFrame(SiteInstance* instance,
921                                              int opener_route_id,
922                                              bool swapped_out,
923                                              bool for_main_frame_navigation,
924                                              bool hidden) {
925  CHECK(instance);
926  DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
927
928  // TODO(nasko): Remove the following CHECK once cross-site navigation no
929  // longer relies on swapped out RFH for the top-level frame.
930  if (!frame_tree_node_->IsMainFrame()) {
931    CHECK(!swapped_out);
932  }
933
934  scoped_ptr<RenderFrameHostImpl> new_render_frame_host;
935  RenderFrameHostImpl* frame_to_announce = NULL;
936  int routing_id = MSG_ROUTING_NONE;
937
938  // We are creating a pending or swapped out RFH here.  We should never create
939  // it in the same SiteInstance as our current RFH.
940  CHECK_NE(render_frame_host_->GetSiteInstance(), instance);
941
942  // Check if we've already created an RFH for this SiteInstance.  If so, try
943  // to re-use the existing one, which has already been initialized.  We'll
944  // remove it from the list of swapped out hosts if it commits.
945  RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
946
947  if (proxy) {
948    routing_id = proxy->GetRenderViewHost()->GetRoutingID();
949    // Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost.
950    // Prevent the process from exiting while we're trying to use it.
951    if (!swapped_out) {
952      new_render_frame_host = proxy->PassFrameHostOwnership();
953      new_render_frame_host->GetProcess()->AddPendingView();
954
955      proxy_hosts_.erase(instance->GetId());
956      delete proxy;
957
958      // When a new render view is created by the renderer, the new WebContents
959      // gets a RenderViewHost in the SiteInstance of its opener WebContents.
960      // If not used in the first navigation, this RVH is swapped out and is not
961      // granted bindings, so we may need to grant them when swapping it in.
962      if (pending_web_ui() &&
963          !new_render_frame_host->GetProcess()->IsIsolatedGuest()) {
964        int required_bindings = pending_web_ui()->GetBindings();
965        RenderViewHost* rvh = new_render_frame_host->render_view_host();
966        if ((rvh->GetEnabledBindings() & required_bindings) !=
967                required_bindings) {
968          rvh->AllowBindings(required_bindings);
969        }
970      }
971    }
972  } else {
973    // Create a new RenderFrameHost if we don't find an existing one.
974    new_render_frame_host = CreateRenderFrameHost(
975        instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, swapped_out, hidden);
976    RenderViewHostImpl* render_view_host =
977        new_render_frame_host->render_view_host();
978    int proxy_routing_id = MSG_ROUTING_NONE;
979
980    // Prevent the process from exiting while we're trying to navigate in it.
981    // Otherwise, if the new RFH is swapped out already, store it.
982    if (!swapped_out) {
983      new_render_frame_host->GetProcess()->AddPendingView();
984    } else {
985      proxy = new RenderFrameProxyHost(
986          new_render_frame_host->GetSiteInstance(), frame_tree_node_);
987      proxy_hosts_[instance->GetId()] = proxy;
988      proxy->TakeFrameHostOwnership(new_render_frame_host.Pass());
989      proxy_routing_id = proxy->GetRoutingID();
990    }
991
992    bool success = InitRenderView(render_view_host,
993                                  opener_route_id,
994                                  proxy_routing_id,
995                                  for_main_frame_navigation);
996    if (success) {
997      if (frame_tree_node_->IsMainFrame()) {
998        // Don't show the main frame's view until we get a DidNavigate from it.
999        render_view_host->GetView()->Hide();
1000      } else if (!swapped_out) {
1001        // Init the RFH, so a RenderFrame is created in the renderer.
1002        DCHECK(new_render_frame_host.get());
1003        success = InitRenderFrame(new_render_frame_host.get());
1004      }
1005      if (swapped_out) {
1006        proxy_hosts_[instance->GetId()]->InitRenderFrameProxy();
1007      }
1008    } else if (!swapped_out && pending_render_frame_host_) {
1009      CancelPending();
1010    }
1011    routing_id = render_view_host->GetRoutingID();
1012    frame_to_announce = new_render_frame_host.get();
1013  }
1014
1015  // Use this as our new pending RFH if it isn't swapped out.
1016  if (!swapped_out)
1017    pending_render_frame_host_ = new_render_frame_host.Pass();
1018
1019  // If a brand new RFH was created, announce it to observers.
1020  if (frame_to_announce)
1021    render_frame_delegate_->RenderFrameCreated(frame_to_announce);
1022
1023  return routing_id;
1024}
1025
1026int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance) {
1027  // A RenderFrameProxyHost should never be created in the same SiteInstance as
1028  // the current RFH.
1029  CHECK(instance);
1030  CHECK_NE(instance, render_frame_host_->GetSiteInstance());
1031
1032  RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
1033  if (proxy)
1034    return proxy->GetRoutingID();
1035
1036  proxy = new RenderFrameProxyHost(instance, frame_tree_node_);
1037  proxy_hosts_[instance->GetId()] = proxy;
1038  proxy->InitRenderFrameProxy();
1039  return proxy->GetRoutingID();
1040}
1041
1042bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host,
1043                                            int opener_route_id,
1044                                            int proxy_routing_id,
1045                                            bool for_main_frame_navigation) {
1046  // We may have initialized this RenderViewHost for another RenderFrameHost.
1047  if (render_view_host->IsRenderViewLive())
1048    return true;
1049
1050  // If the pending navigation is to a WebUI and the RenderView is not in a
1051  // guest process, tell the RenderViewHost about any bindings it will need
1052  // enabled.
1053  if (pending_web_ui() && !render_view_host->GetProcess()->IsIsolatedGuest()) {
1054    render_view_host->AllowBindings(pending_web_ui()->GetBindings());
1055  } else {
1056    // Ensure that we don't create an unprivileged RenderView in a WebUI-enabled
1057    // process unless it's swapped out.
1058    RenderViewHostImpl* rvh_impl =
1059        static_cast<RenderViewHostImpl*>(render_view_host);
1060    if (!rvh_impl->IsSwappedOut()) {
1061      CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1062                render_view_host->GetProcess()->GetID()));
1063    }
1064  }
1065
1066  return delegate_->CreateRenderViewForRenderManager(
1067                                                    render_view_host,
1068                                                    opener_route_id,
1069                                                    proxy_routing_id,
1070                                                    for_main_frame_navigation);
1071}
1072
1073bool RenderFrameHostManager::InitRenderFrame(
1074    RenderFrameHost* render_frame_host) {
1075  RenderFrameHostImpl* rfh =
1076      static_cast<RenderFrameHostImpl*>(render_frame_host);
1077  if (rfh->IsRenderFrameLive())
1078    return true;
1079
1080  int parent_routing_id = MSG_ROUTING_NONE;
1081  if (frame_tree_node_->parent()) {
1082    parent_routing_id = frame_tree_node_->parent()->render_manager()->
1083        GetRoutingIdForSiteInstance(render_frame_host->GetSiteInstance());
1084    CHECK_NE(parent_routing_id, MSG_ROUTING_NONE);
1085  }
1086  return delegate_->CreateRenderFrameForRenderManager(render_frame_host,
1087                                                      parent_routing_id);
1088}
1089
1090int RenderFrameHostManager::GetRoutingIdForSiteInstance(
1091    SiteInstance* site_instance) {
1092  if (render_frame_host_->GetSiteInstance() == site_instance)
1093    return render_frame_host_->GetRoutingID();
1094
1095  RenderFrameProxyHostMap::iterator iter =
1096      proxy_hosts_.find(site_instance->GetId());
1097  if (iter != proxy_hosts_.end())
1098    return iter->second->GetRoutingID();
1099
1100  return MSG_ROUTING_NONE;
1101}
1102
1103void RenderFrameHostManager::CommitPending() {
1104  // First check whether we're going to want to focus the location bar after
1105  // this commit.  We do this now because the navigation hasn't formally
1106  // committed yet, so if we've already cleared |pending_web_ui_| the call chain
1107  // this triggers won't be able to figure out what's going on.
1108  bool will_focus_location_bar = delegate_->FocusLocationBarByDefault();
1109
1110  // We expect SwapOutOldPage to have canceled any modal dialogs and told the
1111  // renderer to suppress any further dialogs until it is swapped out.  However,
1112  // crash reports indicate that it's still possible for modal dialogs to exist
1113  // at this point, which poses a risk if we delete their RenderViewHost below.
1114  // Cancel them again to be safe.  http://crbug.com/324320.
1115  delegate_->CancelModalDialogsForRenderManager();
1116
1117  // Next commit the Web UI, if any. Either replace |web_ui_| with
1118  // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or
1119  // leave |web_ui_| as is if reusing it.
1120  DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get()));
1121  if (pending_web_ui_) {
1122    web_ui_.reset(pending_web_ui_.release());
1123  } else if (!pending_and_current_web_ui_.get()) {
1124    web_ui_.reset();
1125  } else {
1126    DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get());
1127    pending_and_current_web_ui_.reset();
1128  }
1129
1130  // It's possible for the pending_render_frame_host_ to be NULL when we aren't
1131  // crossing process boundaries. If so, we just needed to handle the Web UI
1132  // committing above and we're done.
1133  if (!pending_render_frame_host_) {
1134    if (will_focus_location_bar)
1135      delegate_->SetFocusToLocationBar(false);
1136    return;
1137  }
1138
1139  // Remember if the page was focused so we can focus the new renderer in
1140  // that case.
1141  bool focus_render_view = !will_focus_location_bar &&
1142      render_frame_host_->render_view_host()->GetView() &&
1143      render_frame_host_->render_view_host()->GetView()->HasFocus();
1144
1145  // TODO(creis): As long as show/hide are on RVH, we don't want to do them for
1146  // subframe navigations or they'll interfere with the top-level page.
1147  bool is_main_frame = frame_tree_node_->IsMainFrame();
1148
1149  // Swap in the pending frame and make it active. Also ensure the FrameTree
1150  // stays in sync.
1151  scoped_ptr<RenderFrameHostImpl> old_render_frame_host =
1152      SetRenderFrameHost(pending_render_frame_host_.Pass());
1153  if (is_main_frame)
1154    render_frame_host_->render_view_host()->AttachToFrameTree();
1155
1156  // The process will no longer try to exit, so we can decrement the count.
1157  render_frame_host_->GetProcess()->RemovePendingView();
1158
1159  // If the view is gone, then this RenderViewHost died while it was hidden.
1160  // We ignored the RenderProcessGone call at the time, so we should send it now
1161  // to make sure the sad tab shows up, etc.
1162  if (!render_frame_host_->render_view_host()->GetView()) {
1163    delegate_->RenderProcessGoneFromRenderManager(
1164        render_frame_host_->render_view_host());
1165  } else if (!delegate_->IsHidden()) {
1166    render_frame_host_->render_view_host()->GetView()->Show();
1167  }
1168
1169  // If the old view is live and top-level, hide it now that the new one is
1170  // visible.
1171  int32 old_site_instance_id =
1172      old_render_frame_host->GetSiteInstance()->GetId();
1173  if (old_render_frame_host->render_view_host()->GetView()) {
1174    if (is_main_frame) {
1175      old_render_frame_host->render_view_host()->GetView()->Hide();
1176      old_render_frame_host->render_view_host()->WasSwappedOut(base::Bind(
1177          &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
1178          weak_factory_.GetWeakPtr(),
1179          old_site_instance_id,
1180          old_render_frame_host.get()));
1181    } else {
1182      // TODO(creis): We'll need to set this back to false if we navigate back.
1183      old_render_frame_host->set_swapped_out(true);
1184    }
1185  }
1186
1187  // Make sure the size is up to date.  (Fix for bug 1079768.)
1188  delegate_->UpdateRenderViewSizeForRenderManager();
1189
1190  if (will_focus_location_bar) {
1191    delegate_->SetFocusToLocationBar(false);
1192  } else if (focus_render_view &&
1193             render_frame_host_->render_view_host()->GetView()) {
1194    render_frame_host_->render_view_host()->GetView()->Focus();
1195  }
1196
1197  // Notify that we've swapped RenderFrameHosts. We do this before shutting down
1198  // the RFH so that we can clean up RendererResources related to the RFH first.
1199  delegate_->NotifySwappedFromRenderManager(
1200      old_render_frame_host.get(), render_frame_host_.get(), is_main_frame);
1201
1202  // If the old RFH is not live, just return as there is no work to do.
1203  if (!old_render_frame_host->render_view_host()->IsRenderViewLive()) {
1204    return;
1205  }
1206
1207  // If the old RFH is live, we are swapping it out and should keep track of
1208  // it in case we navigate back to it, or it is waiting for the unload event
1209  // to execute in the background.
1210  // TODO(creis): Swap out the subframe in --site-per-process.
1211  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess))
1212    DCHECK(old_render_frame_host->is_swapped_out() ||
1213           !RenderViewHostImpl::IsRVHStateActive(
1214               old_render_frame_host->render_view_host()->rvh_state()));
1215
1216  // If the RenderViewHost backing the RenderFrameHost is pending shutdown,
1217  // the RenderFrameHost should be put in the map of RenderFrameHosts pending
1218  // shutdown. Otherwise, it is stored in the map of proxy hosts.
1219  if (old_render_frame_host->render_view_host()->rvh_state() ==
1220      RenderViewHostImpl::STATE_PENDING_SHUTDOWN) {
1221    // The proxy for this RenderFrameHost is created when sending the
1222    // SwapOut message, so check if it already exists and delete it.
1223    RenderFrameProxyHostMap::iterator iter =
1224        proxy_hosts_.find(old_site_instance_id);
1225    if (iter != proxy_hosts_.end()) {
1226      delete iter->second;
1227      proxy_hosts_.erase(iter);
1228    }
1229    RFHPendingDeleteMap::iterator pending_delete_iter =
1230        pending_delete_hosts_.find(old_site_instance_id);
1231    if (pending_delete_iter == pending_delete_hosts_.end() ||
1232        pending_delete_iter->second.get() != old_render_frame_host) {
1233      pending_delete_hosts_[old_site_instance_id] =
1234          linked_ptr<RenderFrameHostImpl>(old_render_frame_host.release());
1235    }
1236  } else {
1237    CHECK(proxy_hosts_.find(render_frame_host_->GetSiteInstance()->GetId()) ==
1238          proxy_hosts_.end());
1239
1240    // Capture the active view count on the old RFH SiteInstance, since the
1241    // ownership might be passed into the proxy and the pointer will be
1242    // invalid.
1243    int active_view_count =
1244        static_cast<SiteInstanceImpl*>(old_render_frame_host->GetSiteInstance())
1245            ->active_view_count();
1246
1247    if (is_main_frame) {
1248      RenderFrameProxyHostMap::iterator iter =
1249          proxy_hosts_.find(old_site_instance_id);
1250      CHECK(iter != proxy_hosts_.end());
1251      iter->second->TakeFrameHostOwnership(old_render_frame_host.Pass());
1252    }
1253
1254    // If there are no active views in this SiteInstance, it means that
1255    // this RFH was the last active one in the SiteInstance. Now that we
1256    // know that all RFHs are swapped out, we can delete all the RFPHs and
1257    // RVHs in this SiteInstance.
1258    if (!active_view_count) {
1259      ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id);
1260    } else {
1261      // If this is a subframe, it should have a CrossProcessFrameConnector
1262      // created already and we just need to link it to the proper view in the
1263      // new process.
1264      if (!is_main_frame) {
1265        RenderFrameProxyHost* proxy = GetProxyToParent();
1266        if (proxy) {
1267          proxy->SetChildRWHView(
1268              render_frame_host_->render_view_host()->GetView());
1269        }
1270      }
1271    }
1272  }
1273}
1274
1275void RenderFrameHostManager::ShutdownRenderFrameProxyHostsInSiteInstance(
1276    int32 site_instance_id) {
1277  // First remove any swapped out RFH for this SiteInstance from our own list.
1278  ClearProxiesInSiteInstance(site_instance_id, frame_tree_node_);
1279
1280  // Use the safe RenderWidgetHost iterator for now to find all RenderViewHosts
1281  // in the SiteInstance, then tell their respective FrameTrees to remove all
1282  // RenderFrameProxyHosts corresponding to them.
1283  // TODO(creis): Replace this with a RenderFrameHostIterator that protects
1284  // against use-after-frees if a later element is deleted before getting to it.
1285  scoped_ptr<RenderWidgetHostIterator> widgets(
1286      RenderWidgetHostImpl::GetAllRenderWidgetHosts());
1287  while (RenderWidgetHost* widget = widgets->GetNextHost()) {
1288    if (!widget->IsRenderView())
1289      continue;
1290    RenderViewHostImpl* rvh =
1291        static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget));
1292    if (site_instance_id == rvh->GetSiteInstance()->GetId()) {
1293      // This deletes all RenderFrameHosts using the |rvh|, which then causes
1294      // |rvh| to Shutdown.
1295      FrameTree* tree = rvh->GetDelegate()->GetFrameTree();
1296      tree->ForEach(base::Bind(
1297          &RenderFrameHostManager::ClearProxiesInSiteInstance,
1298          site_instance_id));
1299    }
1300  }
1301}
1302
1303RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
1304    const NavigationEntryImpl& entry) {
1305  // If we are currently navigating cross-process, we want to get back to normal
1306  // and then navigate as usual.
1307  if (cross_navigation_pending_) {
1308    if (pending_render_frame_host_)
1309      CancelPending();
1310    cross_navigation_pending_ = false;
1311  }
1312
1313  SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
1314  scoped_refptr<SiteInstance> new_instance = current_instance;
1315
1316  // We do not currently swap processes for navigations in webview tag guests.
1317  bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme);
1318
1319  // Determine if we need a new BrowsingInstance for this entry.  If true, this
1320  // implies that it will get a new SiteInstance (and likely process), and that
1321  // other tabs in the current BrowsingInstance will be unable to script it.
1322  // This is used for cases that require a process swap even in the
1323  // process-per-tab model, such as WebUI pages.
1324  const NavigationEntry* current_entry =
1325      delegate_->GetLastCommittedNavigationEntryForRenderManager();
1326  BrowserContext* browser_context =
1327      delegate_->GetControllerForRenderManager().GetBrowserContext();
1328  const GURL& current_effective_url = current_entry ?
1329      SiteInstanceImpl::GetEffectiveURL(browser_context,
1330                                        current_entry->GetURL()) :
1331      render_frame_host_->GetSiteInstance()->GetSiteURL();
1332  bool current_is_view_source_mode = current_entry ?
1333      current_entry->IsViewSourceMode() : entry.IsViewSourceMode();
1334  bool force_swap = !is_guest_scheme &&
1335      ShouldSwapBrowsingInstancesForNavigation(
1336          current_effective_url,
1337          current_is_view_source_mode,
1338          entry.site_instance(),
1339          SiteInstanceImpl::GetEffectiveURL(browser_context, entry.GetURL()),
1340          entry.IsViewSourceMode());
1341  if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap)) {
1342    new_instance = GetSiteInstanceForURL(
1343        entry.GetURL(),
1344        entry.site_instance(),
1345        entry.GetTransitionType(),
1346        entry.restore_type() != NavigationEntryImpl::RESTORE_NONE,
1347        entry.IsViewSourceMode(),
1348        current_instance,
1349        force_swap);
1350  }
1351
1352  // If force_swap is true, we must use a different SiteInstance.  If we didn't,
1353  // we would have two RenderFrameHosts in the same SiteInstance and the same
1354  // frame, resulting in page_id conflicts for their NavigationEntries.
1355  if (force_swap)
1356    CHECK_NE(new_instance, current_instance);
1357
1358  if (new_instance != current_instance) {
1359    // New SiteInstance: create a pending RFH to navigate.
1360    DCHECK(!cross_navigation_pending_);
1361
1362    // This will possibly create (set to NULL) a Web UI object for the pending
1363    // page. We'll use this later to give the page special access. This must
1364    // happen before the new renderer is created below so it will get bindings.
1365    // It must also happen after the above conditional call to CancelPending(),
1366    // otherwise CancelPending may clear the pending_web_ui_ and the page will
1367    // not have its bindings set appropriately.
1368    SetPendingWebUI(entry);
1369
1370    // Ensure that we have created RFHs for the new RFH's opener chain if
1371    // we are staying in the same BrowsingInstance. This allows the pending RFH
1372    // to send cross-process script calls to its opener(s).
1373    int opener_route_id = MSG_ROUTING_NONE;
1374    if (new_instance->IsRelatedSiteInstance(current_instance)) {
1375      opener_route_id =
1376          delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
1377
1378      if (CommandLine::ForCurrentProcess()->HasSwitch(
1379              switches::kSitePerProcess)) {
1380        // Ensure that the frame tree has RenderFrameProxyHosts for the new
1381        // SiteInstance in all nodes except the current one.
1382        frame_tree_node_->frame_tree()->CreateProxiesForSiteInstance(
1383            frame_tree_node_, new_instance);
1384      }
1385    }
1386
1387    // Create a non-swapped-out pending RFH with the given opener and navigate
1388    // it.
1389    int route_id = CreateRenderFrame(new_instance,
1390                                     opener_route_id,
1391                                     false,
1392                                     frame_tree_node_->IsMainFrame(),
1393                                     delegate_->IsHidden());
1394    if (route_id == MSG_ROUTING_NONE)
1395      return NULL;
1396
1397    // Check if our current RFH is live before we set up a transition.
1398    if (!render_frame_host_->render_view_host()->IsRenderViewLive()) {
1399      if (!cross_navigation_pending_) {
1400        // The current RFH is not live.  There's no reason to sit around with a
1401        // sad tab or a newly created RFH while we wait for the pending RFH to
1402        // navigate.  Just switch to the pending RFH now and go back to non
1403        // cross-navigating (Note that we don't care about on{before}unload
1404        // handlers if the current RFH isn't live.)
1405        CommitPending();
1406        return render_frame_host_.get();
1407      } else {
1408        NOTREACHED();
1409        return render_frame_host_.get();
1410      }
1411    }
1412    // Otherwise, it's safe to treat this as a pending cross-site transition.
1413
1414    // We need to wait until the beforeunload handler has run, unless we are
1415    // transferring an existing request (in which case it has already run).
1416    // Suspend the new render view (i.e., don't let it send the cross-site
1417    // Navigate message) until we hear back from the old renderer's
1418    // beforeunload handler.  If the handler returns false, we'll have to
1419    // cancel the request.
1420    DCHECK(!pending_render_frame_host_->are_navigations_suspended());
1421    bool is_transfer =
1422        entry.transferred_global_request_id() != GlobalRequestID();
1423    if (is_transfer) {
1424      // We don't need to stop the old renderer or run beforeunload/unload
1425      // handlers, because those have already been done.
1426      DCHECK(pending_nav_params_->global_request_id ==
1427                entry.transferred_global_request_id());
1428    } else {
1429      // Also make sure the old render view stops, in case a load is in
1430      // progress.  (We don't want to do this for transfers, since it will
1431      // interrupt the transfer with an unexpected DidStopLoading.)
1432      render_frame_host_->render_view_host()->Send(new ViewMsg_Stop(
1433          render_frame_host_->render_view_host()->GetRoutingID()));
1434
1435      pending_render_frame_host_->SetNavigationsSuspended(true,
1436                                                          base::TimeTicks());
1437
1438      // Tell the CrossSiteRequestManager that this RFH has a pending cross-site
1439      // request, so that ResourceDispatcherHost will know to tell us to run the
1440      // old page's unload handler before it sends the response.
1441      pending_render_frame_host_->SetHasPendingCrossSiteRequest(true);
1442    }
1443
1444    // We now have a pending RFH.
1445    DCHECK(!cross_navigation_pending_);
1446    cross_navigation_pending_ = true;
1447
1448    // Unless we are transferring an existing request, we should now
1449    // tell the old render view to run its beforeunload handler, since it
1450    // doesn't otherwise know that the cross-site request is happening.  This
1451    // will trigger a call to OnBeforeUnloadACK with the reply.
1452    if (!is_transfer)
1453      render_frame_host_->DispatchBeforeUnload(true);
1454
1455    return pending_render_frame_host_.get();
1456  }
1457
1458  // Otherwise the same SiteInstance can be used.  Navigate render_frame_host_.
1459  DCHECK(!cross_navigation_pending_);
1460
1461  // It's possible to swap out the current RFH and then decide to navigate in it
1462  // anyway (e.g., a cross-process navigation that redirects back to the
1463  // original site).  In that case, we have a proxy for the current RFH but
1464  // haven't deleted it yet.  The new navigation will swap it back in, so we can
1465  // delete the proxy.
1466  DeleteRenderFrameProxyHost(new_instance);
1467
1468  if (ShouldReuseWebUI(current_entry, &entry)) {
1469    pending_web_ui_.reset();
1470    pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
1471  } else {
1472    SetPendingWebUI(entry);
1473
1474    // Make sure the new RenderViewHost has the right bindings.
1475    if (pending_web_ui() &&
1476        !render_frame_host_->GetProcess()->IsIsolatedGuest()) {
1477      render_frame_host_->render_view_host()->AllowBindings(
1478          pending_web_ui()->GetBindings());
1479    }
1480  }
1481
1482  if (pending_web_ui() &&
1483      render_frame_host_->render_view_host()->IsRenderViewLive()) {
1484    pending_web_ui()->GetController()->RenderViewReused(
1485        render_frame_host_->render_view_host());
1486  }
1487
1488  // The renderer can exit view source mode when any error or cancellation
1489  // happen. We must overwrite to recover the mode.
1490  if (entry.IsViewSourceMode()) {
1491    render_frame_host_->render_view_host()->Send(
1492        new ViewMsg_EnableViewSourceMode(
1493            render_frame_host_->render_view_host()->GetRoutingID()));
1494  }
1495
1496  return render_frame_host_.get();
1497}
1498
1499void RenderFrameHostManager::CancelPending() {
1500  scoped_ptr<RenderFrameHostImpl> pending_render_frame_host =
1501      pending_render_frame_host_.Pass();
1502
1503  RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
1504      pending_render_frame_host->render_view_host(),
1505      render_frame_host_->render_view_host());
1506
1507  // We no longer need to prevent the process from exiting.
1508  pending_render_frame_host->GetProcess()->RemovePendingView();
1509
1510  // If the SiteInstance for the pending RFH is being used by others, don't
1511  // delete the RFH, just swap it out and it can be reused at a later point.
1512  SiteInstanceImpl* site_instance = static_cast<SiteInstanceImpl*>(
1513      pending_render_frame_host->GetSiteInstance());
1514  if (site_instance->active_view_count() > 1) {
1515    // Any currently suspended navigations are no longer needed.
1516    pending_render_frame_host->CancelSuspendedNavigations();
1517
1518    RenderFrameProxyHost* proxy =
1519        new RenderFrameProxyHost(site_instance, frame_tree_node_);
1520    proxy_hosts_[site_instance->GetId()] = proxy;
1521    pending_render_frame_host->SwapOut(proxy);
1522    if (frame_tree_node_->IsMainFrame())
1523      proxy->TakeFrameHostOwnership(pending_render_frame_host.Pass());
1524  } else {
1525    // We won't be coming back, so delete this one.
1526    pending_render_frame_host.reset();
1527  }
1528
1529  pending_web_ui_.reset();
1530  pending_and_current_web_ui_.reset();
1531}
1532
1533scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::SetRenderFrameHost(
1534    scoped_ptr<RenderFrameHostImpl> render_frame_host) {
1535  // Swap the two.
1536  scoped_ptr<RenderFrameHostImpl> old_render_frame_host =
1537      render_frame_host_.Pass();
1538  render_frame_host_ = render_frame_host.Pass();
1539
1540  if (frame_tree_node_->IsMainFrame()) {
1541    // Update the count of top-level frames using this SiteInstance.  All
1542    // subframes are in the same BrowsingInstance as the main frame, so we only
1543    // count top-level ones.  This makes the value easier for consumers to
1544    // interpret.
1545    if (render_frame_host_) {
1546      static_cast<SiteInstanceImpl*>(render_frame_host_->GetSiteInstance())->
1547          IncrementRelatedActiveContentsCount();
1548    }
1549    if (old_render_frame_host) {
1550      static_cast<SiteInstanceImpl*>(old_render_frame_host->GetSiteInstance())->
1551          DecrementRelatedActiveContentsCount();
1552    }
1553  }
1554
1555  return old_render_frame_host.Pass();
1556}
1557
1558bool RenderFrameHostManager::IsRVHOnSwappedOutList(
1559    RenderViewHostImpl* rvh) const {
1560  RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(
1561      rvh->GetSiteInstance());
1562  if (!proxy)
1563    return false;
1564  // If there is a proxy without RFH, it is for a subframe in the SiteInstance
1565  // of |rvh|. Subframes should be ignored in this case.
1566  if (!proxy->render_frame_host())
1567    return false;
1568  return IsOnSwappedOutList(proxy->render_frame_host());
1569}
1570
1571bool RenderFrameHostManager::IsOnSwappedOutList(
1572    RenderFrameHostImpl* rfh) const {
1573  if (!rfh->GetSiteInstance())
1574    return false;
1575
1576  RenderFrameProxyHostMap::const_iterator iter = proxy_hosts_.find(
1577      rfh->GetSiteInstance()->GetId());
1578  if (iter == proxy_hosts_.end())
1579    return false;
1580
1581  return iter->second->render_frame_host() == rfh;
1582}
1583
1584RenderViewHostImpl* RenderFrameHostManager::GetSwappedOutRenderViewHost(
1585   SiteInstance* instance) const {
1586  RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
1587  if (proxy)
1588    return proxy->GetRenderViewHost();
1589  return NULL;
1590}
1591
1592RenderFrameProxyHost* RenderFrameHostManager::GetRenderFrameProxyHost(
1593    SiteInstance* instance) const {
1594  RenderFrameProxyHostMap::const_iterator iter =
1595      proxy_hosts_.find(instance->GetId());
1596  if (iter != proxy_hosts_.end())
1597    return iter->second;
1598
1599  return NULL;
1600}
1601
1602void RenderFrameHostManager::DeleteRenderFrameProxyHost(
1603    SiteInstance* instance) {
1604  RenderFrameProxyHostMap::iterator iter = proxy_hosts_.find(instance->GetId());
1605  if (iter != proxy_hosts_.end()) {
1606    delete iter->second;
1607    proxy_hosts_.erase(iter);
1608  }
1609}
1610
1611}  // namespace content
1612