render_frame_host_manager.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Copyright 2013 The Chromium Authors. All rights reserved.
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Use of this source code is governed by a BSD-style license that can be
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// found in the LICENSE file.
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/render_frame_host_manager.h"
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <utility>
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "base/command_line.h"
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "base/debug/trace_event.h"
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "base/logging.h"
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/child_process_security_policy_impl.h"
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/devtools/render_view_devtools_agent_host.h"
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/cross_process_frame_connector.h"
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/cross_site_transferring_request.h"
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/debug_urls.h"
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/interstitial_page_impl.h"
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/navigation_controller_impl.h"
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/navigation_entry_impl.h"
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/navigator.h"
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/render_frame_host_factory.h"
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/frame_host/render_frame_host_impl.h"
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/renderer_host/render_process_host_impl.h"
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/renderer_host/render_view_host_factory.h"
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/renderer_host/render_view_host_impl.h"
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/site_instance_impl.h"
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/webui/web_ui_controller_factory_registry.h"
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/browser/webui/web_ui_impl.h"
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/common/view_messages.h"
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/port/browser/render_widget_host_view_port.h"
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/public/browser/content_browser_client.h"
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/public/browser/notification_service.h"
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/public/browser/notification_types.h"
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/public/browser/render_widget_host_iterator.h"
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/public/browser/user_metrics.h"
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/public/browser/web_ui_controller.h"
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/public/common/content_switches.h"
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "content/public/common/url_constants.h"
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querunamespace content {
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruRenderFrameHostManager::PendingNavigationParams::PendingNavigationParams(
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const GlobalRequestID& global_request_id,
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
4558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    const std::vector<GURL>& transfer_url_chain,
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    Referrer referrer,
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    PageTransition page_transition,
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int render_frame_id,
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool should_replace_current_entry)
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    : global_request_id(global_request_id),
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      cross_site_transferring_request(cross_site_transferring_request.Pass()),
52096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger      transfer_url_chain(transfer_url_chain),
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      referrer(referrer),
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      page_transition(page_transition),
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      render_frame_id(render_frame_id),
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      should_replace_current_entry(should_replace_current_entry) {
57096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruRenderFrameHostManager::PendingNavigationParams::~PendingNavigationParams() {}
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) {
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  node->render_manager()->pending_delete_hosts_.clear();
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return true;
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruRenderFrameHostManager::RenderFrameHostManager(
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    FrameTreeNode* frame_tree_node,
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    RenderFrameHostDelegate* render_frame_delegate,
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    RenderViewHostDelegate* render_view_delegate,
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    RenderWidgetHostDelegate* render_widget_delegate,
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    Delegate* delegate)
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    : frame_tree_node_(frame_tree_node),
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      delegate_(delegate),
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      cross_navigation_pending_(false),
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      render_frame_delegate_(render_frame_delegate),
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      render_view_delegate_(render_view_delegate),
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      render_widget_delegate_(render_widget_delegate),
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      interstitial_page_(NULL),
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      cross_process_frame_connector_(NULL),
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      weak_factory_(this) {}
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruRenderFrameHostManager::~RenderFrameHostManager() {
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (pending_render_frame_host_)
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    CancelPending();
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (cross_process_frame_connector_)
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    delete cross_process_frame_connector_;
8858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // We should always have a current RenderFrameHost except in some tests.
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  render_frame_host_.reset();
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // TODO(creis): Now that we aren't using Shutdown, make RenderFrameHostMap
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // use scoped_ptrs.
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Delete any swapped out RenderFrameHosts.
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru       iter != swapped_out_hosts_.end();
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru       ++iter) {
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    delete iter->second;
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid RenderFrameHostManager::Init(BrowserContext* browser_context,
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  SiteInstance* site_instance,
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  int view_routing_id,
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  int frame_routing_id) {
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Create a RenderViewHost and RenderFrameHost, once we have an instance.  It
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // is important to immediately give this SiteInstance to a RenderViewHost so
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // that the SiteInstance is ref counted.
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (!site_instance)
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    site_instance = SiteInstance::Create(browser_context);
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  render_frame_host_ = make_scoped_ptr(
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      CreateRenderFrameHost(site_instance, view_routing_id, frame_routing_id,
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                            false, delegate_->IsHidden()));
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Keep track of renderer processes as they start to shut down or are
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // crashed/killed.
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                 NotificationService::AllSources());
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSING,
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                 NotificationService::AllSources());
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruRenderViewHostImpl* RenderFrameHostManager::current_host() const {
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (!render_frame_host_)
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return NULL;
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return render_frame_host_->render_view_host();
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruRenderViewHostImpl* RenderFrameHostManager::pending_render_view_host() const {
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (!pending_render_frame_host_)
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return NULL;
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return pending_render_frame_host_->render_view_host();
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruRenderWidgetHostView* RenderFrameHostManager::GetRenderWidgetHostView() const {
13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (interstitial_page_)
13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return interstitial_page_->GetView();
13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (!render_frame_host_)
14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return NULL;
14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return render_frame_host_->render_view_host()->GetView();
14258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger}
14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid RenderFrameHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  pending_web_ui_.reset(
14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      delegate_->CreateWebUIForRenderManager(entry.GetURL()));
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  pending_and_current_web_ui_.reset();
14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
149096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger  // If we have assigned (zero or more) bindings to this NavigationEntry in the
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // past, make sure we're not granting it different bindings than it had
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // before.  If so, note it and don't give it any bindings, to avoid a
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // potential privilege escalation.
15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (pending_web_ui_.get() &&
15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      entry.bindings() != NavigationEntryImpl::kInvalidBindings &&
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      pending_web_ui_->GetBindings() != entry.bindings()) {
15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    RecordAction(
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pending_web_ui_.reset();
15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruRenderFrameHostImpl* RenderFrameHostManager::Navigate(
16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const NavigationEntryImpl& entry) {
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  TRACE_EVENT0("browser", "RenderFrameHostManager:Navigate");
16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Create a pending RenderFrameHost to use for the navigation.
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  RenderFrameHostImpl* dest_render_frame_host =
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      UpdateRendererStateForNavigate(entry);
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (!dest_render_frame_host)
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return NULL;  // We weren't able to create a pending render frame host.
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // If the current render_frame_host_ isn't live, we should create it so
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // that we don't show a sad tab while the dest_render_frame_host fetches
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // its first page.  (Bug 1145340)
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (dest_render_frame_host != render_frame_host_ &&
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      !render_frame_host_->render_view_host()->IsRenderViewLive()) {
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // Note: we don't call InitRenderView here because we are navigating away
17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // soon anyway, and we don't have the NavigationEntry for this host.
17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    delegate_->CreateRenderViewForRenderManager(
17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        render_frame_host_->render_view_host(), MSG_ROUTING_NONE, NULL);
18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // If the renderer crashed, then try to create a new one to satisfy this
18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // navigation request.
18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (!dest_render_frame_host->render_view_host()->IsRenderViewLive()) {
18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // Recreate the opener chain.
18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dest_render_frame_host->render_view_host()->GetSiteInstance());
18858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    if (!InitRenderView(dest_render_frame_host->render_view_host(),
18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        opener_route_id))
19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      return NULL;
19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // Now that we've created a new renderer, be sure to hide it if it isn't
19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // our primary one.  Otherwise, we might crash if we try to call Show()
19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // on it later.
195096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (dest_render_frame_host != render_frame_host_ &&
19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dest_render_frame_host->render_view_host()->GetView()) {
19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      dest_render_frame_host->render_view_host()->GetView()->Hide();
19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else if (frame_tree_node_->IsMainFrame()) {
19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      // This is our primary renderer, notify here as we won't be calling
20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      // CommitPending (which does the notify).  We only do this for top-level
20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      // frames.
20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      delegate_->NotifySwappedFromRenderManager(
20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          NULL, render_frame_host_->render_view_host());
20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // If entry includes the request ID of a request that is being transferred,
20880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // the destination render frame will take ownership, so release ownership of
20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // the request.
21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (pending_nav_params_ &&
21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      pending_nav_params_->global_request_id ==
21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          entry.transferred_global_request_id()) {
21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pending_nav_params_->cross_site_transferring_request->ReleaseRequest();
21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return dest_render_frame_host;
21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid RenderFrameHostManager::Stop() {
22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  render_frame_host_->render_view_host()->Stop();
22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // If we are cross-navigating, we should stop the pending renderers.  This
22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // will lead to a DidFailProvisionalLoad, which will properly destroy them.
22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (cross_navigation_pending_) {
22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pending_render_frame_host_->render_view_host()->Send(new ViewMsg_Stop(
22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pending_render_frame_host_->render_view_host()->GetRoutingID()));
22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid RenderFrameHostManager::SetIsLoading(bool is_loading) {
23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  render_frame_host_->render_view_host()->SetIsLoading(is_loading);
23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (pending_render_frame_host_)
23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pending_render_frame_host_->render_view_host()->SetIsLoading(is_loading);
23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (!cross_navigation_pending_)
23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return true;
23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // We should always have a pending RFH when there's a cross-process navigation
24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // in progress.  Sanity check this for http://crbug.com/276333.
24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  CHECK(pending_render_frame_host_);
24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // If the tab becomes unresponsive during {before}unload while doing a
24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // cross-site navigation, proceed with the navigation.  (This assumes that
24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // the pending RenderFrameHost is still responsive.)
24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (render_frame_host_->render_view_host()->IsWaitingForUnloadACK()) {
24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // The request has been started and paused while we're waiting for the
249    // unload handler to finish.  We'll pretend that it did.  The pending
250    // renderer will then be swapped in as part of the usual DidNavigate logic.
251    // (If the unload handler later finishes, this call will be ignored because
252    // the pending_nav_params_ state will already be cleaned up.)
253    current_host()->OnSwappedOut(true);
254  } else if (render_frame_host_->render_view_host()->
255                 is_waiting_for_beforeunload_ack()) {
256    // Haven't gotten around to starting the request, because we're still
257    // waiting for the beforeunload handler to finish.  We'll pretend that it
258    // did finish, to let the navigation proceed.  Note that there's a danger
259    // that the beforeunload handler will later finish and possibly return
260    // false (meaning the navigation should not proceed), but we'll ignore it
261    // in this case because it took too long.
262    if (pending_render_frame_host_->render_view_host()->
263            are_navigations_suspended()) {
264      pending_render_frame_host_->render_view_host()->SetNavigationsSuspended(
265          false, base::TimeTicks::Now());
266    }
267  }
268  return false;
269}
270
271void RenderFrameHostManager::OnBeforeUnloadACK(
272    bool for_cross_site_transition,
273    bool proceed,
274    const base::TimeTicks& proceed_time) {
275  if (for_cross_site_transition) {
276    // Ignore if we're not in a cross-site navigation.
277    if (!cross_navigation_pending_)
278      return;
279
280    if (proceed) {
281      // Ok to unload the current page, so proceed with the cross-site
282      // navigation.  Note that if navigations are not currently suspended, it
283      // might be because the renderer was deemed unresponsive and this call was
284      // already made by ShouldCloseTabOnUnresponsiveRenderer.  In that case, it
285      // is ok to do nothing here.
286      if (pending_render_frame_host_ &&
287          pending_render_frame_host_->render_view_host()->
288              are_navigations_suspended()) {
289        pending_render_frame_host_->render_view_host()->
290            SetNavigationsSuspended(false, proceed_time);
291      }
292    } else {
293      // Current page says to cancel.
294      CancelPending();
295      cross_navigation_pending_ = false;
296    }
297  } else {
298    // Non-cross site transition means closing the entire tab.
299    bool proceed_to_fire_unload;
300    delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
301                                                  &proceed_to_fire_unload);
302
303    if (proceed_to_fire_unload) {
304      // If we're about to close the tab and there's a pending RFH, cancel it.
305      // Otherwise, if the navigation in the pending RFH completes before the
306      // close in the current RFH, we'll lose the tab close.
307      if (pending_render_frame_host_) {
308        CancelPending();
309        cross_navigation_pending_ = false;
310      }
311
312      // This is not a cross-site navigation, the tab is being closed.
313      render_frame_host_->render_view_host()->ClosePage();
314    }
315  }
316}
317
318void RenderFrameHostManager::OnCrossSiteResponse(
319    RenderFrameHostImpl* pending_render_frame_host,
320    const GlobalRequestID& global_request_id,
321    scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
322    const std::vector<GURL>& transfer_url_chain,
323    const Referrer& referrer,
324    PageTransition page_transition,
325    bool should_replace_current_entry) {
326  // This should be called either when the pending RFH is ready to commit or
327  // when we realize that the current RFH's request requires a transfer.
328  DCHECK(pending_render_frame_host == pending_render_frame_host_ ||
329         pending_render_frame_host == render_frame_host_);
330
331  // TODO(creis): Eventually we will want to check all navigation responses
332  // here, but currently we pass information for a transfer if
333  // ShouldSwapProcessesForRedirect returned true in the network stack.
334  // In that case, we should set up a transfer after the unload handler runs.
335  // If |cross_site_transferring_request| is NULL, we will just run the unload
336  // handler and resume.
337  pending_nav_params_.reset(new PendingNavigationParams(
338      global_request_id, cross_site_transferring_request.Pass(),
339      transfer_url_chain, referrer, page_transition,
340      pending_render_frame_host->GetRoutingID(),
341      should_replace_current_entry));
342
343  // Run the unload handler of the current page.
344  SwapOutOldPage();
345}
346
347// TODO(creis): Remove this in favor of SwappedOutFrame.
348void RenderFrameHostManager::SwappedOut(RenderViewHost* render_view_host) {
349  // Make sure this is from our current RVH, and that we have a pending
350  // navigation from OnCrossSiteResponse.  (There may be no pending navigation
351  // for data URLs that don't make network requests, for example.)   If not,
352  // just return early and ignore.
353  if (render_view_host != render_frame_host_->render_view_host() ||
354      !pending_nav_params_.get()) {
355    pending_nav_params_.reset();
356    return;
357  }
358
359  // Now that the unload handler has run, we need to either initiate the
360  // pending transfer (if there is one) or resume the paused response (if not).
361  // TODO(creis): The blank swapped out page is visible during this time, but
362  // we can shorten this by delivering the response directly, rather than
363  // forcing an identical request to be made.
364  if (pending_nav_params_->cross_site_transferring_request) {
365    // Treat the last URL in the chain as the destination and the remainder as
366    // the redirect chain.
367    CHECK(pending_nav_params_->transfer_url_chain.size());
368    GURL transfer_url = pending_nav_params_->transfer_url_chain.back();
369    pending_nav_params_->transfer_url_chain.pop_back();
370
371    // We use GetMainFrame here because this version of SwappedOut is only
372    // called for the main frame.  We will remove it in favor of the frame
373    // specific version.
374    RenderFrameHostImpl* render_frame_host =
375        static_cast<RenderFrameHostImpl*>(render_view_host->GetMainFrame());
376
377    // We don't know whether the original request had |user_action| set to true.
378    // However, since we force the navigation to be in the current tab, it
379    // doesn't matter.
380    render_frame_host->frame_tree_node()->navigator()->RequestTransferURL(
381        render_frame_host,
382        transfer_url,
383        pending_nav_params_->transfer_url_chain,
384        pending_nav_params_->referrer,
385        pending_nav_params_->page_transition,
386        CURRENT_TAB,
387        pending_nav_params_->global_request_id,
388        pending_nav_params_->should_replace_current_entry,
389        true);
390  } else if (pending_render_frame_host_) {
391    RenderProcessHostImpl* pending_process =
392        static_cast<RenderProcessHostImpl*>(
393            pending_render_frame_host_->GetProcess());
394    pending_process->ResumeDeferredNavigation(
395        pending_nav_params_->global_request_id);
396  }
397  pending_nav_params_.reset();
398}
399
400void RenderFrameHostManager::SwappedOutFrame(
401    RenderFrameHostImpl* render_frame_host) {
402  // Make sure this is from our current RFH, and that we have a pending
403  // navigation from OnCrossSiteResponse.  (There may be no pending navigation
404  // for data URLs that don't make network requests, for example.)   If not,
405  // just return early and ignore.
406  if (render_frame_host != render_frame_host_ || !pending_nav_params_.get()) {
407    pending_nav_params_.reset();
408    return;
409  }
410
411  // Sanity check that this is for the correct frame.
412  DCHECK_EQ(render_frame_host_->GetRoutingID(),
413            pending_nav_params_->render_frame_id);
414  DCHECK_EQ(render_frame_host_->GetProcess()->GetID(),
415            pending_nav_params_->global_request_id.child_id);
416
417  // Now that the unload handler has run, we need to either initiate the
418  // pending transfer (if there is one) or resume the paused response (if not).
419  // TODO(creis): The blank swapped out page is visible during this time, but
420  // we can shorten this by delivering the response directly, rather than
421  // forcing an identical request to be made.
422  if (pending_nav_params_->cross_site_transferring_request) {
423    // Treat the last URL in the chain as the destination and the remainder as
424    // the redirect chain.
425    CHECK(pending_nav_params_->transfer_url_chain.size());
426    GURL transfer_url = pending_nav_params_->transfer_url_chain.back();
427    pending_nav_params_->transfer_url_chain.pop_back();
428
429    // We don't know whether the original request had |user_action| set to true.
430    // However, since we force the navigation to be in the current tab, it
431    // doesn't matter.
432    render_frame_host_->frame_tree_node()->navigator()->RequestTransferURL(
433        render_frame_host,
434        transfer_url,
435        pending_nav_params_->transfer_url_chain,
436        pending_nav_params_->referrer,
437        pending_nav_params_->page_transition,
438        CURRENT_TAB,
439        pending_nav_params_->global_request_id,
440        false,
441        true);
442  } else if (pending_render_frame_host_) {
443    RenderProcessHostImpl* pending_process =
444        static_cast<RenderProcessHostImpl*>(
445            pending_render_frame_host_->GetProcess());
446    pending_process->ResumeDeferredNavigation(
447        pending_nav_params_->global_request_id);
448  }
449  pending_nav_params_.reset();
450}
451
452// TODO(creis): This should take in a RenderFrameHost.
453void RenderFrameHostManager::DidNavigateMainFrame(
454    RenderViewHost* render_view_host) {
455  if (!cross_navigation_pending_) {
456    DCHECK(!pending_render_frame_host_);
457
458    // We should only hear this from our current renderer.
459    DCHECK(render_view_host == render_frame_host_->render_view_host());
460
461    // Even when there is no pending RVH, there may be a pending Web UI.
462    if (pending_web_ui())
463      CommitPending();
464    return;
465  }
466
467  if (render_view_host == pending_render_frame_host_->render_view_host()) {
468    // The pending cross-site navigation completed, so show the renderer.
469    // If it committed without sending network requests (e.g., data URLs),
470    // then we still need to swap out the old RFH first and run its unload
471    // handler.  OK for that to happen in the background.
472    if (pending_render_frame_host_->render_view_host()->
473            HasPendingCrossSiteRequest())
474      SwapOutOldPage();
475
476    CommitPending();
477    cross_navigation_pending_ = false;
478  } else if (render_view_host == render_frame_host_->render_view_host()) {
479    // A navigation in the original page has taken place.  Cancel the pending
480    // one.
481    CancelPending();
482    cross_navigation_pending_ = false;
483  } else {
484    // No one else should be sending us DidNavigate in this state.
485    DCHECK(false);
486  }
487}
488
489// TODO(creis): Take in RenderFrameHost instead, since frames can have openers.
490void RenderFrameHostManager::DidDisownOpener(RenderViewHost* render_view_host) {
491  // Notify all swapped out hosts, including the pending RVH.
492  for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
493       iter != swapped_out_hosts_.end();
494       ++iter) {
495    DCHECK_NE(iter->second->render_view_host()->GetSiteInstance(),
496              current_host()->GetSiteInstance());
497    iter->second->render_view_host()->DisownOpener();
498  }
499}
500
501void RenderFrameHostManager::RendererProcessClosing(
502    RenderProcessHost* render_process_host) {
503  // Remove any swapped out RVHs from this process, so that we don't try to
504  // swap them back in while the process is exiting.  Start by finding them,
505  // since there could be more than one.
506  std::list<int> ids_to_remove;
507  for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
508       iter != swapped_out_hosts_.end();
509       ++iter) {
510    if (iter->second->GetProcess() == render_process_host)
511      ids_to_remove.push_back(iter->first);
512  }
513
514  // Now delete them.
515  while (!ids_to_remove.empty()) {
516    delete swapped_out_hosts_[ids_to_remove.back()];
517    swapped_out_hosts_.erase(ids_to_remove.back());
518    ids_to_remove.pop_back();
519  }
520}
521
522void RenderFrameHostManager::SwapOutOldPage() {
523  // Should only see this while we have a pending renderer or transfer.
524  CHECK(cross_navigation_pending_ || pending_nav_params_.get());
525
526  // Tell the renderer to suppress any further modal dialogs so that we can swap
527  // it out.  This must be done before canceling any current dialog, in case
528  // there is a loop creating additional dialogs.
529  render_frame_host_->render_view_host()->SuppressDialogsUntilSwapOut();
530
531  // Now close any modal dialogs that would prevent us from swapping out.  This
532  // must be done separately from SwapOut, so that the PageGroupLoadDeferrer is
533  // no longer on the stack when we send the SwapOut message.
534  delegate_->CancelModalDialogsForRenderManager();
535
536  // Tell the old renderer it is being swapped out.  This will fire the unload
537  // handler (without firing the beforeunload handler a second time).  When the
538  // unload handler finishes and the navigation completes, we will send a
539  // message to the ResourceDispatcherHost, allowing the pending RVH's response
540  // to resume.
541  // Note: This must be done on the RFH or else we'll swap out the top-level
542  // page when subframes navigate.
543  if (frame_tree_node_->IsMainFrame()) {
544    render_frame_host_->render_view_host()->SwapOut();
545  } else {
546    // The RenderFrameHost being swapped out becomes the proxy for this
547    // frame in its parent's process. CrossProcessFrameConnector
548    // initialization only needs to happen on an initial cross-process
549    // navigation, when the RenderFrame leaves the same process as its parent.
550    // The same CrossProcessFrameConnector is used for subsequent cross-
551    // process navigations, but it will be destroyed if the Frame is
552    // navigated back to the same site instance as its parent.
553    // TODO(kenrb): This will change when RenderFrameProxyHost is created.
554    if (!cross_process_frame_connector_) {
555      cross_process_frame_connector_ =
556          new CrossProcessFrameConnector(render_frame_host_.get());
557    }
558    render_frame_host_->SwapOut();
559  }
560
561  // ResourceDispatcherHost has told us to run the onunload handler, which
562  // means it is not a download or unsafe page, and we are going to perform the
563  // navigation.  Thus, we no longer need to remember that the RenderFrameHost
564  // is part of a pending cross-site request.
565  if (pending_render_frame_host_) {
566    pending_render_frame_host_->render_view_host()->
567        SetHasPendingCrossSiteRequest(false);
568  }
569}
570
571void RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance(
572    int32 site_instance_id,
573    RenderFrameHostImpl* rfh) {
574  RFHPendingDeleteMap::iterator iter =
575      pending_delete_hosts_.find(site_instance_id);
576  if (iter != pending_delete_hosts_.end() && iter->second.get() == rfh)
577    pending_delete_hosts_.erase(site_instance_id);
578}
579
580void RenderFrameHostManager::Observe(
581    int type,
582    const NotificationSource& source,
583    const NotificationDetails& details) {
584  switch (type) {
585    case NOTIFICATION_RENDERER_PROCESS_CLOSED:
586    case NOTIFICATION_RENDERER_PROCESS_CLOSING:
587      RendererProcessClosing(
588          Source<RenderProcessHost>(source).ptr());
589      break;
590
591    default:
592      NOTREACHED();
593  }
594}
595
596bool RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance(
597    int32 site_instance_id,
598    FrameTreeNode* node) {
599  RenderFrameHostMap::iterator iter =
600      node->render_manager()->swapped_out_hosts_.find(site_instance_id);
601  if (iter != node->render_manager()->swapped_out_hosts_.end()) {
602    RenderFrameHostImpl* swapped_out_rfh = iter->second;
603    // If the RVH is pending swap out, it needs to switch state to
604    // pending shutdown. Otherwise it is deleted.
605    if (swapped_out_rfh->render_view_host()->rvh_state() ==
606        RenderViewHostImpl::STATE_PENDING_SWAP_OUT) {
607      swapped_out_rfh->SetPendingShutdown(base::Bind(
608          &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
609          node->render_manager()->weak_factory_.GetWeakPtr(),
610          site_instance_id,
611          swapped_out_rfh));
612      RFHPendingDeleteMap::iterator pending_delete_iter =
613          node->render_manager()->pending_delete_hosts_.find(site_instance_id);
614      if (pending_delete_iter ==
615              node->render_manager()->pending_delete_hosts_.end() ||
616          pending_delete_iter->second.get() != iter->second) {
617        node->render_manager()->pending_delete_hosts_[site_instance_id] =
618            linked_ptr<RenderFrameHostImpl>(swapped_out_rfh);
619      }
620    } else {
621      delete swapped_out_rfh;
622    }
623    node->render_manager()->swapped_out_hosts_.erase(site_instance_id);
624  }
625
626  return true;
627}
628
629bool RenderFrameHostManager::ShouldTransitionCrossSite() {
630  // False in the single-process mode, as it makes RVHs to accumulate
631  // in swapped_out_hosts_.
632  // True if we are using process-per-site-instance (default) or
633  // process-per-site (kProcessPerSite).
634  return
635      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
636      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab);
637}
638
639bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
640    const NavigationEntry* current_entry,
641    const NavigationEntryImpl* new_entry) const {
642  DCHECK(new_entry);
643
644  // If new_entry already has a SiteInstance, assume it is correct.  We only
645  // need to force a swap if it is in a different BrowsingInstance.
646  if (new_entry->site_instance()) {
647    return !new_entry->site_instance()->IsRelatedSiteInstance(
648        render_frame_host_->GetSiteInstance());
649  }
650
651  // Check for reasons to swap processes even if we are in a process model that
652  // doesn't usually swap (e.g., process-per-tab).  Any time we return true,
653  // the new_entry will be rendered in a new SiteInstance AND BrowsingInstance.
654
655  // We use the effective URL here, since that's what is used in the
656  // SiteInstance's site and when we later call IsSameWebSite.  If there is no
657  // current_entry, check the current SiteInstance's site, which might already
658  // be committed to a Web UI URL (such as the NTP).
659  BrowserContext* browser_context =
660      delegate_->GetControllerForRenderManager().GetBrowserContext();
661  const GURL& current_url = (current_entry) ?
662      SiteInstanceImpl::GetEffectiveURL(browser_context,
663                                        current_entry->GetURL()) :
664      render_frame_host_->render_view_host()->GetSiteInstance()->GetSiteURL();
665  const GURL& new_url = SiteInstanceImpl::GetEffectiveURL(browser_context,
666                                                          new_entry->GetURL());
667
668  // Don't force a new BrowsingInstance for debug URLs that are handled in the
669  // renderer process, like javascript: or chrome://crash.
670  if (IsRendererDebugURL(new_url))
671    return false;
672
673  // For security, we should transition between processes when one is a Web UI
674  // page and one isn't.
675  if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
676          browser_context, current_url)) {
677    // If so, force a swap if destination is not an acceptable URL for Web UI.
678    // Here, data URLs are never allowed.
679    if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
680            browser_context, new_url)) {
681      return true;
682    }
683  } else {
684    // Force a swap if it's a Web UI URL.
685    if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
686            browser_context, new_url)) {
687      return true;
688    }
689  }
690
691  // Check with the content client as well.  Important to pass current_url here,
692  // which uses the SiteInstance's site if there is no current_entry.
693  if (GetContentClient()->browser()->ShouldSwapBrowsingInstancesForNavigation(
694          render_frame_host_->render_view_host()->GetSiteInstance(),
695          current_url, new_url)) {
696    return true;
697  }
698
699  // We can't switch a RenderView between view source and non-view source mode
700  // without screwing up the session history sometimes (when navigating between
701  // "view-source:http://foo.com/" and "http://foo.com/", Blink doesn't treat
702  // it as a new navigation). So require a BrowsingInstance switch.
703  if (current_entry &&
704      current_entry->IsViewSourceMode() != new_entry->IsViewSourceMode())
705    return true;
706
707  return false;
708}
709
710bool RenderFrameHostManager::ShouldReuseWebUI(
711    const NavigationEntry* current_entry,
712    const NavigationEntryImpl* new_entry) const {
713  NavigationControllerImpl& controller =
714      delegate_->GetControllerForRenderManager();
715  return current_entry && web_ui_.get() &&
716      (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
717          controller.GetBrowserContext(), current_entry->GetURL()) ==
718       WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
719          controller.GetBrowserContext(), new_entry->GetURL()));
720}
721
722SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
723    const NavigationEntryImpl& entry,
724    SiteInstance* current_instance,
725    bool force_browsing_instance_swap) {
726  // Determine which SiteInstance to use for navigating to |entry|.
727  const GURL& dest_url = entry.GetURL();
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 (entry.site_instance()) {
734    // If we are forcing a swap, this should be in a different BrowsingInstance.
735    if (force_browsing_instance_swap) {
736      CHECK(!entry.site_instance()->IsRelatedSiteInstance(
737                render_frame_host_->GetSiteInstance()));
738    }
739    return entry.site_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(entry.GetTransitionType(),
759                               PAGE_TRANSITION_GENERATED)) {
760    return current_instance;
761  }
762
763  SiteInstanceImpl* current_site_instance =
764      static_cast<SiteInstanceImpl*>(current_instance);
765
766  // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it
767  // for this entry.  We won't commit the SiteInstance to this site until the
768  // navigation commits (in DidNavigate), unless the navigation entry was
769  // restored or it's a Web UI as described below.
770  if (!current_site_instance->HasSite()) {
771    // If we've already created a SiteInstance for our destination, we don't
772    // want to use this unused SiteInstance; use the existing one.  (We don't
773    // do this check if the current_instance has a site, because for now, we
774    // want to compare against the current URL and not the SiteInstance's site.
775    // In this case, there is no current URL, so comparing against the site is
776    // ok.  See additional comments below.)
777    //
778    // Also, if the URL should use process-per-site mode and there is an
779    // existing process for the site, we should use it.  We can call
780    // GetRelatedSiteInstance() for this, which will eagerly set the site and
781    // thus use the correct process.
782    bool use_process_per_site =
783        RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
784        RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
785    if (current_site_instance->HasRelatedSiteInstance(dest_url) ||
786        use_process_per_site) {
787      return current_site_instance->GetRelatedSiteInstance(dest_url);
788    }
789
790    // For extensions, Web UI URLs (such as the new tab page), and apps we do
791    // not want to use the current_instance if it has no site, since it will
792    // have a RenderProcessHost of PRIV_NORMAL.  Create a new SiteInstance for
793    // this URL instead (with the correct process type).
794    if (current_site_instance->HasWrongProcessForURL(dest_url))
795      return current_site_instance->GetRelatedSiteInstance(dest_url);
796
797    // View-source URLs must use a new SiteInstance and BrowsingInstance.
798    // TODO(nasko): This is the same condition as later in the function. This
799    // should be taken into account when refactoring this method as part of
800    // http://crbug.com/123007.
801    if (entry.IsViewSourceMode())
802      return SiteInstance::CreateForURL(browser_context, dest_url);
803
804    // If we are navigating from a blank SiteInstance to a WebUI, make sure we
805    // create a new SiteInstance.
806    if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
807            browser_context, dest_url)) {
808        return SiteInstance::CreateForURL(browser_context, dest_url);
809    }
810
811    // Normally the "site" on the SiteInstance is set lazily when the load
812    // actually commits. This is to support better process sharing in case
813    // the site redirects to some other site: we want to use the destination
814    // site in the site instance.
815    //
816    // In the case of session restore, as it loads all the pages immediately
817    // we need to set the site first, otherwise after a restore none of the
818    // pages would share renderers in process-per-site.
819    if (entry.restore_type() != NavigationEntryImpl::RESTORE_NONE)
820      current_site_instance->SetSite(dest_url);
821
822    return current_site_instance;
823  }
824
825  // Otherwise, only create a new SiteInstance for a cross-site navigation.
826
827  // TODO(creis): Once we intercept links and script-based navigations, we
828  // will be able to enforce that all entries in a SiteInstance actually have
829  // the same site, and it will be safe to compare the URL against the
830  // SiteInstance's site, as follows:
831  // const GURL& current_url = current_instance->site();
832  // For now, though, we're in a hybrid model where you only switch
833  // SiteInstances if you type in a cross-site URL.  This means we have to
834  // compare the entry's URL to the last committed entry's URL.
835  NavigationEntry* current_entry = controller.GetLastCommittedEntry();
836  if (interstitial_page_) {
837    // The interstitial is currently the last committed entry, but we want to
838    // compare against the last non-interstitial entry.
839    current_entry = controller.GetEntryAtOffset(-1);
840  }
841  // If there is no last non-interstitial entry (and current_instance already
842  // has a site), then we must have been opened from another tab.  We want
843  // to compare against the URL of the page that opened us, but we can't
844  // get to it directly.  The best we can do is check against the site of
845  // the SiteInstance.  This will be correct when we intercept links and
846  // script-based navigations, but for now, it could place some pages in a
847  // new process unnecessarily.  We should only hit this case if a page tries
848  // to open a new tab to an interstitial-inducing URL, and then navigates
849  // the page to a different same-site URL.  (This seems very unlikely in
850  // practice.)
851  const GURL& current_url = (current_entry) ? current_entry->GetURL() :
852      current_instance->GetSiteURL();
853
854  // View-source URLs must use a new SiteInstance and BrowsingInstance.
855  // We don't need a swap when going from view-source to a debug URL like
856  // chrome://crash, however.
857  // TODO(creis): Refactor this method so this duplicated code isn't needed.
858  // See http://crbug.com/123007.
859  if (current_entry &&
860      current_entry->IsViewSourceMode() != entry.IsViewSourceMode() &&
861      !IsRendererDebugURL(dest_url)) {
862    return SiteInstance::CreateForURL(browser_context, dest_url);
863  }
864
865  // Use the current SiteInstance for same site navigations, as long as the
866  // process type is correct.  (The URL may have been installed as an app since
867  // the last time we visited it.)
868  if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
869      !current_site_instance->HasWrongProcessForURL(dest_url)) {
870    return current_instance;
871  }
872
873  // Start the new renderer in a new SiteInstance, but in the current
874  // BrowsingInstance.  It is important to immediately give this new
875  // SiteInstance to a RenderViewHost (if it is different than our current
876  // SiteInstance), so that it is ref counted.  This will happen in
877  // CreateRenderView.
878  return current_instance->GetRelatedSiteInstance(dest_url);
879}
880
881RenderFrameHostImpl* RenderFrameHostManager::CreateRenderFrameHost(
882    SiteInstance* site_instance,
883    int view_routing_id,
884    int frame_routing_id,
885    bool swapped_out,
886    bool hidden) {
887  if (frame_routing_id == MSG_ROUTING_NONE)
888    frame_routing_id = site_instance->GetProcess()->GetNextRoutingID();
889
890  // Create a RVH for main frames, or find the existing one for subframes.
891  FrameTree* frame_tree = frame_tree_node_->frame_tree();
892  RenderViewHostImpl* render_view_host = NULL;
893  if (frame_tree_node_->IsMainFrame()) {
894    render_view_host = frame_tree->CreateRenderViewHostForMainFrame(
895        site_instance, view_routing_id, frame_routing_id, swapped_out, hidden);
896  } else {
897    render_view_host = frame_tree->GetRenderViewHostForSubFrame(site_instance);
898
899    // If we haven't found a RVH for a subframe RFH, it's because we currently
900    // do not create top-level RFHs for pending subframe navigations.  Create
901    // the RVH here for now.
902    // TODO(creis): Mirror the frame tree so this check isn't necessary.
903    if (!render_view_host) {
904      render_view_host = frame_tree->CreateRenderViewHostForMainFrame(
905          site_instance, view_routing_id, frame_routing_id, swapped_out,
906          hidden);
907    }
908  }
909
910  // TODO(creis): Make render_frame_host a scoped_ptr.
911  // TODO(creis): Pass hidden to RFH.
912  RenderFrameHostImpl* render_frame_host =
913      RenderFrameHostFactory::Create(render_view_host,
914                                     render_frame_delegate_,
915                                     frame_tree,
916                                     frame_tree_node_,
917                                     frame_routing_id,
918                                     swapped_out).release();
919  return render_frame_host;
920}
921
922int RenderFrameHostManager::CreateRenderFrame(
923    SiteInstance* instance,
924    int opener_route_id,
925    bool swapped_out,
926    bool hidden) {
927  CHECK(instance);
928  DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
929
930  // We are creating a pending or swapped out RFH here.  We should never create
931  // it in the same SiteInstance as our current RFH.
932  CHECK_NE(render_frame_host_->render_view_host()->GetSiteInstance(), instance);
933
934  // Check if we've already created an RFH for this SiteInstance.  If so, try
935  // to re-use the existing one, which has already been initialized.  We'll
936  // remove it from the list of swapped out hosts if it commits.
937  RenderFrameHostImpl* new_render_frame_host =
938      GetSwappedOutRenderFrameHost(instance);
939
940  FrameTreeNode* parent_node = NULL;
941  if (frame_tree_node_)
942    parent_node = frame_tree_node_->parent();
943
944  if (new_render_frame_host) {
945    // Prevent the process from exiting while we're trying to use it.
946    if (!swapped_out) {
947      new_render_frame_host->GetProcess()->AddPendingView();
948    } else {
949      // Detect if this is a cross-process child frame that is navigating
950      // back to the same SiteInstance as its parent.
951      if (parent_node && cross_process_frame_connector_ &&
952          render_frame_host_->GetSiteInstance() == parent_node->
953              render_manager()->current_frame_host()->GetSiteInstance()) {
954        delete cross_process_frame_connector_;
955        cross_process_frame_connector_ = NULL;
956      }
957    }
958  } else {
959    // Create a new RenderFrameHost if we don't find an existing one.
960    // TODO(creis): Make new_render_frame_host a scoped_ptr.
961    new_render_frame_host = CreateRenderFrameHost(instance, MSG_ROUTING_NONE,
962                                                  MSG_ROUTING_NONE, swapped_out,
963                                                  hidden);
964
965    // If the new RFH is swapped out already, store it.  Otherwise prevent the
966    // process from exiting while we're trying to navigate in it.
967    if (swapped_out) {
968      swapped_out_hosts_[instance->GetId()] = new_render_frame_host;
969    } else {
970      new_render_frame_host->GetProcess()->AddPendingView();
971    }
972
973    RenderViewHostImpl* render_view_host =
974        new_render_frame_host->render_view_host();
975    bool success = InitRenderView(render_view_host, opener_route_id);
976    if (success && frame_tree_node_->IsMainFrame()) {
977      // Don't show the main frame's view until we get a DidNavigate from it.
978      render_view_host->GetView()->Hide();
979    } else if (!swapped_out && pending_render_frame_host_) {
980      CancelPending();
981    }
982  }
983
984  // Use this as our new pending RFH if it isn't swapped out.
985  if (!swapped_out)
986    pending_render_frame_host_.reset(new_render_frame_host);
987
988  return new_render_frame_host->render_view_host()->GetRoutingID();
989}
990
991bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host,
992                                            int opener_route_id) {
993  // We may have initialized this RenderViewHost for another RenderFrameHost.
994  if (render_view_host->IsRenderViewLive())
995    return true;
996
997  // If the pending navigation is to a WebUI and the RenderView is not in a
998  // guest process, tell the RenderViewHost about any bindings it will need
999  // enabled.
1000  if (pending_web_ui() && !render_view_host->GetProcess()->IsGuest()) {
1001    render_view_host->AllowBindings(pending_web_ui()->GetBindings());
1002  } else {
1003    // Ensure that we don't create an unprivileged RenderView in a WebUI-enabled
1004    // process unless it's swapped out.
1005    RenderViewHostImpl* rvh_impl =
1006        static_cast<RenderViewHostImpl*>(render_view_host);
1007    if (!rvh_impl->IsSwappedOut()) {
1008      CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
1009                render_view_host->GetProcess()->GetID()));
1010    }
1011  }
1012
1013  return delegate_->CreateRenderViewForRenderManager(
1014      render_view_host, opener_route_id, cross_process_frame_connector_);
1015}
1016
1017void RenderFrameHostManager::CommitPending() {
1018  // First check whether we're going to want to focus the location bar after
1019  // this commit.  We do this now because the navigation hasn't formally
1020  // committed yet, so if we've already cleared |pending_web_ui_| the call chain
1021  // this triggers won't be able to figure out what's going on.
1022  bool will_focus_location_bar = delegate_->FocusLocationBarByDefault();
1023
1024  // We expect SwapOutOldPage to have canceled any modal dialogs and told the
1025  // renderer to suppress any further dialogs until it is swapped out.  However,
1026  // crash reports indicate that it's still possible for modal dialogs to exist
1027  // at this point, which poses a risk if we delete their RenderViewHost below.
1028  // Cancel them again to be safe.  http://crbug.com/324320.
1029  delegate_->CancelModalDialogsForRenderManager();
1030
1031  // Next commit the Web UI, if any. Either replace |web_ui_| with
1032  // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or
1033  // leave |web_ui_| as is if reusing it.
1034  DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get()));
1035  if (pending_web_ui_) {
1036    web_ui_.reset(pending_web_ui_.release());
1037  } else if (!pending_and_current_web_ui_.get()) {
1038    web_ui_.reset();
1039  } else {
1040    DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get());
1041    pending_and_current_web_ui_.reset();
1042  }
1043
1044  // It's possible for the pending_render_frame_host_ to be NULL when we aren't
1045  // crossing process boundaries. If so, we just needed to handle the Web UI
1046  // committing above and we're done.
1047  if (!pending_render_frame_host_) {
1048    if (will_focus_location_bar)
1049      delegate_->SetFocusToLocationBar(false);
1050    return;
1051  }
1052
1053  // Remember if the page was focused so we can focus the new renderer in
1054  // that case.
1055  bool focus_render_view = !will_focus_location_bar &&
1056      render_frame_host_->render_view_host()->GetView() &&
1057      render_frame_host_->render_view_host()->GetView()->HasFocus();
1058
1059  // TODO(creis): As long as show/hide are on RVH, we don't want to do them for
1060  // subframe navigations or they'll interfere with the top-level page.
1061  bool is_main_frame = frame_tree_node_->IsMainFrame();
1062
1063  // Swap in the pending frame and make it active. Also ensure the FrameTree
1064  // stays in sync.
1065  RenderFrameHostImpl* old_render_frame_host = render_frame_host_.release();
1066  render_frame_host_ = pending_render_frame_host_.Pass();
1067  if (is_main_frame)
1068    render_frame_host_->render_view_host()->AttachToFrameTree();
1069
1070  // The process will no longer try to exit, so we can decrement the count.
1071  render_frame_host_->GetProcess()->RemovePendingView();
1072
1073  // If the view is gone, then this RenderViewHost died while it was hidden.
1074  // We ignored the RenderProcessGone call at the time, so we should send it now
1075  // to make sure the sad tab shows up, etc.
1076  if (!render_frame_host_->render_view_host()->GetView()) {
1077    delegate_->RenderProcessGoneFromRenderManager(
1078        render_frame_host_->render_view_host());
1079  } else if (!delegate_->IsHidden()) {
1080    render_frame_host_->render_view_host()->GetView()->Show();
1081  }
1082
1083  // If the old view is live and top-level, hide it now that the new one is
1084  // visible.
1085  int32 old_site_instance_id =
1086      old_render_frame_host->render_view_host()->GetSiteInstance()->GetId();
1087  if (old_render_frame_host->render_view_host()->GetView()) {
1088    if (is_main_frame) {
1089      old_render_frame_host->render_view_host()->GetView()->Hide();
1090      old_render_frame_host->render_view_host()->WasSwappedOut(base::Bind(
1091          &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
1092          weak_factory_.GetWeakPtr(),
1093          old_site_instance_id,
1094          old_render_frame_host));
1095    } else {
1096      // TODO(creis): We'll need to set this back to false if we navigate back.
1097      old_render_frame_host->set_swapped_out(true);
1098    }
1099  }
1100
1101  // Make sure the size is up to date.  (Fix for bug 1079768.)
1102  delegate_->UpdateRenderViewSizeForRenderManager();
1103
1104  if (will_focus_location_bar) {
1105    delegate_->SetFocusToLocationBar(false);
1106  } else if (focus_render_view &&
1107             render_frame_host_->render_view_host()->GetView()) {
1108    RenderWidgetHostViewPort::FromRWHV(
1109        render_frame_host_->render_view_host()->GetView())->Focus();
1110  }
1111
1112  // Notify that we've swapped RenderFrameHosts. We do this before shutting down
1113  // the RFH so that we can clean up RendererResources related to the RFH first.
1114  // TODO(creis): Only do this on top-level RFHs for now, and later update it to
1115  // pass the RFHs.
1116  if (is_main_frame) {
1117    delegate_->NotifySwappedFromRenderManager(
1118        old_render_frame_host->render_view_host(),
1119        render_frame_host_->render_view_host());
1120  }
1121
1122  // If the pending frame was on the swapped out list, we can remove it.
1123  swapped_out_hosts_.erase(render_frame_host_->render_view_host()->
1124                               GetSiteInstance()->GetId());
1125
1126  if (old_render_frame_host->render_view_host()->IsRenderViewLive()) {
1127    // If the old RFH is live, we are swapping it out and should keep track of
1128    // it in case we navigate back to it, or it is waiting for the unload event
1129    // to execute in the background.
1130    // TODO(creis): Swap out the subframe in --site-per-process.
1131    if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess))
1132      DCHECK(old_render_frame_host->is_swapped_out() ||
1133             !RenderViewHostImpl::IsRVHStateActive(
1134                  old_render_frame_host->render_view_host()->rvh_state()));
1135    // Temp fix for http://crbug.com/90867 until we do a better cleanup to make
1136    // sure we don't get different rvh instances for the same site instance
1137    // in the same rvhmgr.
1138    // TODO(creis): Clean this up.
1139    RenderFrameHostMap::iterator iter =
1140        swapped_out_hosts_.find(old_site_instance_id);
1141    if (iter != swapped_out_hosts_.end() &&
1142        iter->second != old_render_frame_host) {
1143      // Delete the RFH that will be replaced in the map to avoid a leak.
1144      delete iter->second;
1145    }
1146    // If the RenderViewHost backing the RenderFrameHost is pending shutdown,
1147    // the RenderFrameHost should be put in the map of RenderFrameHosts pending
1148    // shutdown. Otherwise, it is stored in the map of swapped out
1149    // RenderFrameHosts.
1150    if (old_render_frame_host->render_view_host()->rvh_state() ==
1151            RenderViewHostImpl::STATE_PENDING_SHUTDOWN) {
1152      swapped_out_hosts_.erase(old_site_instance_id);
1153      RFHPendingDeleteMap::iterator pending_delete_iter =
1154          pending_delete_hosts_.find(old_site_instance_id);
1155      if (pending_delete_iter == pending_delete_hosts_.end() ||
1156          pending_delete_iter->second.get() != old_render_frame_host) {
1157        pending_delete_hosts_[old_site_instance_id] =
1158            linked_ptr<RenderFrameHostImpl>(old_render_frame_host);
1159      }
1160    } else {
1161      swapped_out_hosts_[old_site_instance_id] = old_render_frame_host;
1162    }
1163
1164    // If there are no active views in this SiteInstance, it means that
1165    // this RFH was the last active one in the SiteInstance. Now that we
1166    // know that all RFHs are swapped out, we can delete all the RFHs and RVHs
1167    // in this SiteInstance.  We do this after ensuring the RFH is on the
1168    // swapped out list to simplify the deletion.
1169    if (!static_cast<SiteInstanceImpl*>(
1170            old_render_frame_host->render_view_host()->GetSiteInstance())->
1171                active_view_count()) {
1172      ShutdownRenderFrameHostsInSiteInstance(old_site_instance_id);
1173      // This is deleted while cleaning up the SiteInstance's views.
1174      old_render_frame_host = NULL;
1175    }
1176  } else {
1177    delete old_render_frame_host;
1178  }
1179}
1180
1181void RenderFrameHostManager::ShutdownRenderFrameHostsInSiteInstance(
1182    int32 site_instance_id) {
1183  // First remove any swapped out RFH for this SiteInstance from our own list.
1184  ClearSwappedOutRFHsInSiteInstance(site_instance_id, frame_tree_node_);
1185
1186  // Use the safe RenderWidgetHost iterator for now to find all RenderViewHosts
1187  // in the SiteInstance, then tell their respective FrameTrees to remove all
1188  // swapped out RenderFrameHosts corresponding to them.
1189  // TODO(creis): Replace this with a RenderFrameHostIterator that protects
1190  // against use-after-frees if a later element is deleted before getting to it.
1191  scoped_ptr<RenderWidgetHostIterator> widgets(
1192      RenderWidgetHostImpl::GetAllRenderWidgetHosts());
1193  while (RenderWidgetHost* widget = widgets->GetNextHost()) {
1194    if (!widget->IsRenderView())
1195      continue;
1196    RenderViewHostImpl* rvh =
1197        static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget));
1198    if (site_instance_id == rvh->GetSiteInstance()->GetId()) {
1199      // This deletes all RenderFrameHosts using the |rvh|, which then causes
1200      // |rvh| to Shutdown.
1201      FrameTree* tree = rvh->GetDelegate()->GetFrameTree();
1202      tree->ForEach(base::Bind(
1203          &RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance,
1204          site_instance_id));
1205    }
1206  }
1207}
1208
1209RenderFrameHostImpl* RenderFrameHostManager::UpdateRendererStateForNavigate(
1210    const NavigationEntryImpl& entry) {
1211  // If we are currently navigating cross-process, we want to get back to normal
1212  // and then navigate as usual.
1213  if (cross_navigation_pending_) {
1214    if (pending_render_frame_host_)
1215      CancelPending();
1216    cross_navigation_pending_ = false;
1217  }
1218
1219  // render_frame_host_'s SiteInstance and new_instance will not be deleted
1220  // before the end of this method, so we don't have to worry about their ref
1221  // counts dropping to zero.
1222  SiteInstance* current_instance =
1223      render_frame_host_->render_view_host()->GetSiteInstance();
1224  SiteInstance* new_instance = current_instance;
1225
1226  // We do not currently swap processes for navigations in webview tag guests.
1227  bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme);
1228
1229  // Determine if we need a new BrowsingInstance for this entry.  If true, this
1230  // implies that it will get a new SiteInstance (and likely process), and that
1231  // other tabs in the current BrowsingInstance will be unable to script it.
1232  // This is used for cases that require a process swap even in the
1233  // process-per-tab model, such as WebUI pages.
1234  const NavigationEntry* current_entry =
1235      delegate_->GetLastCommittedNavigationEntryForRenderManager();
1236  bool force_swap = !is_guest_scheme &&
1237      ShouldSwapBrowsingInstancesForNavigation(current_entry, &entry);
1238  if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
1239    new_instance = GetSiteInstanceForEntry(entry, current_instance, force_swap);
1240
1241  // If force_swap is true, we must use a different SiteInstance.  If we didn't,
1242  // we would have two RenderFrameHosts in the same SiteInstance and the same
1243  // frame, resulting in page_id conflicts for their NavigationEntries.
1244  if (force_swap)
1245    CHECK_NE(new_instance, current_instance);
1246
1247  if (new_instance != current_instance) {
1248    // New SiteInstance: create a pending RFH to navigate.
1249    DCHECK(!cross_navigation_pending_);
1250
1251    // This will possibly create (set to NULL) a Web UI object for the pending
1252    // page. We'll use this later to give the page special access. This must
1253    // happen before the new renderer is created below so it will get bindings.
1254    // It must also happen after the above conditional call to CancelPending(),
1255    // otherwise CancelPending may clear the pending_web_ui_ and the page will
1256    // not have its bindings set appropriately.
1257    SetPendingWebUI(entry);
1258
1259    // Ensure that we have created RFHs for the new RFH's opener chain if
1260    // we are staying in the same BrowsingInstance. This allows the pending RFH
1261    // to send cross-process script calls to its opener(s).
1262    int opener_route_id = MSG_ROUTING_NONE;
1263    if (new_instance->IsRelatedSiteInstance(current_instance)) {
1264      opener_route_id =
1265          delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
1266    }
1267
1268    // Create a non-swapped-out pending RFH with the given opener and navigate
1269    // it.
1270    int route_id = CreateRenderFrame(new_instance, opener_route_id, false,
1271                                     delegate_->IsHidden());
1272    if (route_id == MSG_ROUTING_NONE)
1273      return NULL;
1274
1275    // Check if our current RFH is live before we set up a transition.
1276    if (!render_frame_host_->render_view_host()->IsRenderViewLive()) {
1277      if (!cross_navigation_pending_) {
1278        // The current RFH is not live.  There's no reason to sit around with a
1279        // sad tab or a newly created RFH while we wait for the pending RFH to
1280        // navigate.  Just switch to the pending RFH now and go back to non
1281        // cross-navigating (Note that we don't care about on{before}unload
1282        // handlers if the current RFH isn't live.)
1283        CommitPending();
1284        return render_frame_host_.get();
1285      } else {
1286        NOTREACHED();
1287        return render_frame_host_.get();
1288      }
1289    }
1290    // Otherwise, it's safe to treat this as a pending cross-site transition.
1291
1292    // We need to wait until the beforeunload handler has run, unless we are
1293    // transferring an existing request (in which case it has already run).
1294    // Suspend the new render view (i.e., don't let it send the cross-site
1295    // Navigate message) until we hear back from the old renderer's
1296    // beforeunload handler.  If the handler returns false, we'll have to
1297    // cancel the request.
1298    DCHECK(!pending_render_frame_host_->render_view_host()->
1299               are_navigations_suspended());
1300    bool is_transfer =
1301        entry.transferred_global_request_id() != GlobalRequestID();
1302    if (is_transfer) {
1303      // We don't need to stop the old renderer or run beforeunload/unload
1304      // handlers, because those have already been done.
1305      DCHECK(pending_nav_params_->global_request_id ==
1306                entry.transferred_global_request_id());
1307    } else {
1308      // Also make sure the old render view stops, in case a load is in
1309      // progress.  (We don't want to do this for transfers, since it will
1310      // interrupt the transfer with an unexpected DidStopLoading.)
1311      render_frame_host_->render_view_host()->Send(new ViewMsg_Stop(
1312          render_frame_host_->render_view_host()->GetRoutingID()));
1313
1314      pending_render_frame_host_->render_view_host()->SetNavigationsSuspended(
1315          true, base::TimeTicks());
1316
1317      // Tell the CrossSiteRequestManager that this RVH has a pending cross-site
1318      // request, so that ResourceDispatcherHost will know to tell us to run the
1319      // old page's unload handler before it sends the response.
1320      // TODO(creis): This needs to be on the RFH.
1321      pending_render_frame_host_->render_view_host()->
1322          SetHasPendingCrossSiteRequest(true);
1323    }
1324
1325    // We now have a pending RFH.
1326    DCHECK(!cross_navigation_pending_);
1327    cross_navigation_pending_ = true;
1328
1329    // Unless we are transferring an existing request, we should now
1330    // tell the old render view to run its beforeunload handler, since it
1331    // doesn't otherwise know that the cross-site request is happening.  This
1332    // will trigger a call to OnBeforeUnloadACK with the reply.
1333    if (!is_transfer)
1334      render_frame_host_->DispatchBeforeUnload(true);
1335
1336    return pending_render_frame_host_.get();
1337  }
1338
1339  // Otherwise the same SiteInstance can be used.  Navigate render_frame_host_.
1340  DCHECK(!cross_navigation_pending_);
1341  if (ShouldReuseWebUI(current_entry, &entry)) {
1342    pending_web_ui_.reset();
1343    pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
1344  } else {
1345    SetPendingWebUI(entry);
1346
1347    // Make sure the new RenderViewHost has the right bindings.
1348    if (pending_web_ui() && !render_frame_host_->GetProcess()->IsGuest()) {
1349      render_frame_host_->render_view_host()->AllowBindings(
1350          pending_web_ui()->GetBindings());
1351    }
1352  }
1353
1354  if (pending_web_ui() &&
1355      render_frame_host_->render_view_host()->IsRenderViewLive()) {
1356    pending_web_ui()->GetController()->RenderViewReused(
1357        render_frame_host_->render_view_host());
1358  }
1359
1360  // The renderer can exit view source mode when any error or cancellation
1361  // happen. We must overwrite to recover the mode.
1362  if (entry.IsViewSourceMode()) {
1363    render_frame_host_->render_view_host()->Send(
1364        new ViewMsg_EnableViewSourceMode(
1365            render_frame_host_->render_view_host()->GetRoutingID()));
1366  }
1367
1368  return render_frame_host_.get();
1369}
1370
1371void RenderFrameHostManager::CancelPending() {
1372  RenderFrameHostImpl* pending_render_frame_host =
1373      pending_render_frame_host_.release();
1374
1375  RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
1376      pending_render_frame_host->render_view_host(),
1377      render_frame_host_->render_view_host());
1378
1379  // We no longer need to prevent the process from exiting.
1380  pending_render_frame_host->GetProcess()->RemovePendingView();
1381
1382  // The pending RFH may already be on the swapped out list if we started to
1383  // swap it back in and then canceled.  If so, make sure it gets swapped out
1384  // again.  If it's not on the swapped out list (e.g., aborting a pending
1385  // load), then it's safe to shut down.
1386  if (IsOnSwappedOutList(pending_render_frame_host)) {
1387    // Any currently suspended navigations are no longer needed.
1388    pending_render_frame_host->render_view_host()->CancelSuspendedNavigations();
1389
1390    // TODO(creis): We need to swap out the RFH.
1391    pending_render_frame_host->render_view_host()->SwapOut();
1392  } else {
1393    // We won't be coming back, so shut this one down.
1394    delete pending_render_frame_host;
1395  }
1396
1397  pending_web_ui_.reset();
1398  pending_and_current_web_ui_.reset();
1399}
1400
1401void RenderFrameHostManager::RenderViewDeleted(RenderViewHost* rvh) {
1402  // We are doing this in order to work around and to track a crasher
1403  // (http://crbug.com/23411) where it seems that pending_render_frame_host_ is
1404  // deleted (not sure from where) but not NULLed.
1405  if (pending_render_frame_host_ &&
1406      rvh == pending_render_frame_host_->render_view_host()) {
1407    // If you hit this NOTREACHED, please report it in the following bug
1408    // http://crbug.com/23411 Make sure to include what you were doing when it
1409    // happened  (navigating to a new page, closing a tab...) and if you can
1410    // reproduce.
1411    NOTREACHED();
1412    pending_render_frame_host_.reset();
1413  }
1414
1415  // Make sure deleted RVHs are not kept in the swapped out list while we are
1416  // still alive.  (If render_frame_host_ is null, we're already being deleted.)
1417  if (!render_frame_host_)
1418    return;
1419
1420  // We can't look it up by SiteInstance ID, which may no longer be valid.
1421  for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
1422       iter != swapped_out_hosts_.end();
1423       ++iter) {
1424    if (iter->second->render_view_host() == rvh) {
1425      swapped_out_hosts_.erase(iter);
1426      break;
1427    }
1428  }
1429}
1430
1431bool RenderFrameHostManager::IsRVHOnSwappedOutList(
1432    RenderViewHostImpl* rvh) const {
1433  RenderFrameHostImpl* render_frame_host = GetSwappedOutRenderFrameHost(
1434      rvh->GetSiteInstance());
1435  if (!render_frame_host)
1436    return false;
1437  return IsOnSwappedOutList(render_frame_host);
1438}
1439
1440bool RenderFrameHostManager::IsOnSwappedOutList(
1441    RenderFrameHostImpl* rfh) const {
1442  if (!rfh->render_view_host()->GetSiteInstance())
1443    return false;
1444
1445  RenderFrameHostMap::const_iterator iter = swapped_out_hosts_.find(
1446      rfh->render_view_host()->GetSiteInstance()->GetId());
1447  if (iter == swapped_out_hosts_.end())
1448    return false;
1449
1450  return iter->second == rfh;
1451}
1452
1453RenderViewHostImpl* RenderFrameHostManager::GetSwappedOutRenderViewHost(
1454   SiteInstance* instance) const {
1455  RenderFrameHostImpl* render_frame_host =
1456      GetSwappedOutRenderFrameHost(instance);
1457  if (render_frame_host)
1458    return render_frame_host->render_view_host();
1459  return NULL;
1460}
1461
1462RenderFrameHostImpl* RenderFrameHostManager::GetSwappedOutRenderFrameHost(
1463    SiteInstance* instance) const {
1464  RenderFrameHostMap::const_iterator iter =
1465      swapped_out_hosts_.find(instance->GetId());
1466  if (iter != swapped_out_hosts_.end())
1467    return iter->second;
1468
1469  return NULL;
1470}
1471
1472}  // namespace content
1473