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