This source file includes following definitions.
- should_replace_current_entry
- ClearRFHsPendingShutdown
- weak_factory_
- Init
- current_host
- pending_render_view_host
- GetRenderWidgetHostView
- SetPendingWebUI
- Navigate
- Stop
- SetIsLoading
- ShouldCloseTabOnUnresponsiveRenderer
- OnBeforeUnloadACK
- OnCrossSiteResponse
- SwappedOut
- DidNavigateFrame
- DidDisownOpener
- RendererProcessClosing
- SwapOutOldPage
- ClearPendingShutdownRFHForSiteInstance
- Observe
- ClearSwappedOutRFHsInSiteInstance
- ShouldTransitionCrossSite
- ShouldSwapBrowsingInstancesForNavigation
- ShouldReuseWebUI
- GetSiteInstanceForEntry
- CreateRenderFrameHost
- CreateRenderFrame
- InitRenderView
- CommitPending
- ShutdownRenderFrameHostsInSiteInstance
- UpdateRendererStateForNavigate
- CancelPending
- RenderViewDeleted
- IsRVHOnSwappedOutList
- IsOnSwappedOutList
- GetSwappedOutRenderViewHost
- GetSwappedOutRenderFrameHost
#include "content/browser/frame_host/render_frame_host_manager.h"
#include <utility>
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/devtools/render_view_devtools_agent_host.h"
#include "content/browser/frame_host/cross_process_frame_connector.h"
#include "content/browser/frame_host/cross_site_transferring_request.h"
#include "content/browser/frame_host/debug_urls.h"
#include "content/browser/frame_host/interstitial_page_impl.h"
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/frame_host/render_frame_host_factory.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/site_instance_impl.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/browser/webui/web_ui_impl.h"
#include "content/common/view_messages.h"
#include "content/port/browser/render_widget_host_view_port.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
namespace content {
RenderFrameHostManager::PendingNavigationParams::PendingNavigationParams(
const GlobalRequestID& global_request_id,
scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
const std::vector<GURL>& transfer_url_chain,
Referrer referrer,
PageTransition page_transition,
int render_frame_id,
bool should_replace_current_entry)
: global_request_id(global_request_id),
cross_site_transferring_request(cross_site_transferring_request.Pass()),
transfer_url_chain(transfer_url_chain),
referrer(referrer),
page_transition(page_transition),
render_frame_id(render_frame_id),
should_replace_current_entry(should_replace_current_entry) {
}
RenderFrameHostManager::PendingNavigationParams::~PendingNavigationParams() {}
bool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) {
node->render_manager()->pending_delete_hosts_.clear();
return true;
}
RenderFrameHostManager::RenderFrameHostManager(
FrameTreeNode* frame_tree_node,
RenderFrameHostDelegate* render_frame_delegate,
RenderViewHostDelegate* render_view_delegate,
RenderWidgetHostDelegate* render_widget_delegate,
Delegate* delegate)
: frame_tree_node_(frame_tree_node),
delegate_(delegate),
cross_navigation_pending_(false),
render_frame_delegate_(render_frame_delegate),
render_view_delegate_(render_view_delegate),
render_widget_delegate_(render_widget_delegate),
interstitial_page_(NULL),
cross_process_frame_connector_(NULL),
weak_factory_(this) {}
RenderFrameHostManager::~RenderFrameHostManager() {
if (pending_render_frame_host_)
CancelPending();
if (cross_process_frame_connector_)
delete cross_process_frame_connector_;
render_frame_host_.reset();
for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
iter != swapped_out_hosts_.end();
++iter) {
delete iter->second;
}
}
void RenderFrameHostManager::Init(BrowserContext* browser_context,
SiteInstance* site_instance,
int view_routing_id,
int frame_routing_id) {
if (!site_instance)
site_instance = SiteInstance::Create(browser_context);
render_frame_host_ = make_scoped_ptr(
CreateRenderFrameHost(site_instance, view_routing_id, frame_routing_id,
false, delegate_->IsHidden()));
registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
NotificationService::AllSources());
registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSING,
NotificationService::AllSources());
}
RenderViewHostImpl* RenderFrameHostManager::current_host() const {
if (!render_frame_host_)
return NULL;
return render_frame_host_->render_view_host();
}
RenderViewHostImpl* RenderFrameHostManager::pending_render_view_host() const {
if (!pending_render_frame_host_)
return NULL;
return pending_render_frame_host_->render_view_host();
}
RenderWidgetHostView* RenderFrameHostManager::GetRenderWidgetHostView() const {
if (interstitial_page_)
return interstitial_page_->GetView();
if (!render_frame_host_)
return NULL;
return render_frame_host_->render_view_host()->GetView();
}
void RenderFrameHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
pending_web_ui_.reset(
delegate_->CreateWebUIForRenderManager(entry.GetURL()));
pending_and_current_web_ui_.reset();
if (pending_web_ui_.get() &&
entry.bindings() != NavigationEntryImpl::kInvalidBindings &&
pending_web_ui_->GetBindings() != entry.bindings()) {
RecordAction(
base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
pending_web_ui_.reset();
}
}
RenderFrameHostImpl* RenderFrameHostManager::Navigate(
const NavigationEntryImpl& entry) {
TRACE_EVENT0("browser", "RenderFrameHostManager:Navigate");
RenderFrameHostImpl* dest_render_frame_host =
UpdateRendererStateForNavigate(entry);
if (!dest_render_frame_host)
return NULL;
if (dest_render_frame_host != render_frame_host_ &&
!render_frame_host_->render_view_host()->IsRenderViewLive()) {
delegate_->CreateRenderViewForRenderManager(
render_frame_host_->render_view_host(), MSG_ROUTING_NONE, NULL);
}
if (!dest_render_frame_host->render_view_host()->IsRenderViewLive()) {
int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
dest_render_frame_host->GetSiteInstance());
if (!InitRenderView(dest_render_frame_host->render_view_host(),
opener_route_id))
return NULL;
if (dest_render_frame_host != render_frame_host_ &&
dest_render_frame_host->render_view_host()->GetView()) {
dest_render_frame_host->render_view_host()->GetView()->Hide();
} else if (frame_tree_node_->IsMainFrame()) {
delegate_->NotifySwappedFromRenderManager(
NULL, render_frame_host_->render_view_host());
}
}
if (pending_nav_params_ &&
pending_nav_params_->global_request_id ==
entry.transferred_global_request_id()) {
pending_nav_params_->cross_site_transferring_request->ReleaseRequest();
}
return dest_render_frame_host;
}
void RenderFrameHostManager::Stop() {
render_frame_host_->render_view_host()->Stop();
if (cross_navigation_pending_) {
pending_render_frame_host_->render_view_host()->Send(new ViewMsg_Stop(
pending_render_frame_host_->render_view_host()->GetRoutingID()));
}
}
void RenderFrameHostManager::SetIsLoading(bool is_loading) {
render_frame_host_->render_view_host()->SetIsLoading(is_loading);
if (pending_render_frame_host_)
pending_render_frame_host_->render_view_host()->SetIsLoading(is_loading);
}
bool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
if (!cross_navigation_pending_)
return true;
CHECK(pending_render_frame_host_);
if (render_frame_host_->render_view_host()->IsWaitingForUnloadACK()) {
current_host()->OnSwappedOut(true);
} else if (render_frame_host_->render_view_host()->
is_waiting_for_beforeunload_ack()) {
if (pending_render_frame_host_->render_view_host()->
are_navigations_suspended()) {
pending_render_frame_host_->render_view_host()->SetNavigationsSuspended(
false, base::TimeTicks::Now());
}
}
return false;
}
void RenderFrameHostManager::OnBeforeUnloadACK(
bool for_cross_site_transition,
bool proceed,
const base::TimeTicks& proceed_time) {
if (for_cross_site_transition) {
if (!cross_navigation_pending_)
return;
if (proceed) {
if (pending_render_frame_host_ &&
pending_render_frame_host_->render_view_host()->
are_navigations_suspended()) {
pending_render_frame_host_->render_view_host()->
SetNavigationsSuspended(false, proceed_time);
}
} else {
CancelPending();
cross_navigation_pending_ = false;
}
} else {
bool proceed_to_fire_unload;
delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
&proceed_to_fire_unload);
if (proceed_to_fire_unload) {
if (pending_render_frame_host_) {
CancelPending();
cross_navigation_pending_ = false;
}
render_frame_host_->render_view_host()->ClosePage();
}
}
}
void RenderFrameHostManager::OnCrossSiteResponse(
RenderFrameHostImpl* pending_render_frame_host,
const GlobalRequestID& global_request_id,
scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
const std::vector<GURL>& transfer_url_chain,
const Referrer& referrer,
PageTransition page_transition,
bool should_replace_current_entry) {
DCHECK(pending_render_frame_host == pending_render_frame_host_ ||
pending_render_frame_host == render_frame_host_);
pending_nav_params_.reset(new PendingNavigationParams(
global_request_id, cross_site_transferring_request.Pass(),
transfer_url_chain, referrer, page_transition,
pending_render_frame_host->GetRoutingID(),
should_replace_current_entry));
SwapOutOldPage();
}
void RenderFrameHostManager::SwappedOut(
RenderFrameHostImpl* render_frame_host) {
if (render_frame_host != render_frame_host_ || !pending_nav_params_.get()) {
pending_nav_params_.reset();
return;
}
if (pending_nav_params_->cross_site_transferring_request) {
int render_frame_id = pending_render_frame_host_ ?
pending_render_frame_host_->GetRoutingID() :
render_frame_host_->GetRoutingID();
DCHECK_EQ(render_frame_id, pending_nav_params_->render_frame_id);
int process_id = pending_render_frame_host_ ?
pending_render_frame_host_->GetProcess()->GetID() :
render_frame_host_->GetProcess()->GetID();
DCHECK_EQ(process_id, pending_nav_params_->global_request_id.child_id);
CHECK(pending_nav_params_->transfer_url_chain.size());
GURL transfer_url = pending_nav_params_->transfer_url_chain.back();
pending_nav_params_->transfer_url_chain.pop_back();
render_frame_host->frame_tree_node()->navigator()->RequestTransferURL(
render_frame_host,
transfer_url,
pending_nav_params_->transfer_url_chain,
pending_nav_params_->referrer,
pending_nav_params_->page_transition,
CURRENT_TAB,
pending_nav_params_->global_request_id,
pending_nav_params_->should_replace_current_entry,
true);
} else if (pending_render_frame_host_) {
RenderProcessHostImpl* pending_process =
static_cast<RenderProcessHostImpl*>(
pending_render_frame_host_->GetProcess());
pending_process->ResumeDeferredNavigation(
pending_nav_params_->global_request_id);
}
pending_nav_params_.reset();
}
void RenderFrameHostManager::DidNavigateFrame(
RenderFrameHostImpl* render_frame_host) {
if (!cross_navigation_pending_) {
DCHECK(!pending_render_frame_host_);
DCHECK_EQ(render_frame_host_, render_frame_host);
if (pending_web_ui())
CommitPending();
return;
}
if (render_frame_host == pending_render_frame_host_) {
if (pending_render_frame_host_->render_view_host()->
HasPendingCrossSiteRequest() &&
pending_render_frame_host_->render_view_host()->rvh_state() ==
RenderViewHostImpl::STATE_DEFAULT) {
SwapOutOldPage();
}
CommitPending();
cross_navigation_pending_ = false;
} else if (render_frame_host == render_frame_host_) {
CancelPending();
cross_navigation_pending_ = false;
} else {
DCHECK(false);
}
}
void RenderFrameHostManager::DidDisownOpener(RenderViewHost* render_view_host) {
for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
iter != swapped_out_hosts_.end();
++iter) {
DCHECK_NE(iter->second->GetSiteInstance(),
current_frame_host()->GetSiteInstance());
iter->second->render_view_host()->DisownOpener();
}
}
void RenderFrameHostManager::RendererProcessClosing(
RenderProcessHost* render_process_host) {
std::list<int> ids_to_remove;
for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
iter != swapped_out_hosts_.end();
++iter) {
if (iter->second->GetProcess() == render_process_host)
ids_to_remove.push_back(iter->first);
}
while (!ids_to_remove.empty()) {
delete swapped_out_hosts_[ids_to_remove.back()];
swapped_out_hosts_.erase(ids_to_remove.back());
ids_to_remove.pop_back();
}
}
void RenderFrameHostManager::SwapOutOldPage() {
CHECK(cross_navigation_pending_ || pending_nav_params_.get());
render_frame_host_->render_view_host()->SuppressDialogsUntilSwapOut();
delegate_->CancelModalDialogsForRenderManager();
if (!frame_tree_node_->IsMainFrame()) {
if (!cross_process_frame_connector_) {
cross_process_frame_connector_ =
new CrossProcessFrameConnector(render_frame_host_.get());
}
}
render_frame_host_->SwapOut();
if (pending_render_frame_host_) {
pending_render_frame_host_->render_view_host()->
SetHasPendingCrossSiteRequest(false);
}
}
void RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance(
int32 site_instance_id,
RenderFrameHostImpl* rfh) {
RFHPendingDeleteMap::iterator iter =
pending_delete_hosts_.find(site_instance_id);
if (iter != pending_delete_hosts_.end() && iter->second.get() == rfh)
pending_delete_hosts_.erase(site_instance_id);
}
void RenderFrameHostManager::Observe(
int type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type) {
case NOTIFICATION_RENDERER_PROCESS_CLOSED:
case NOTIFICATION_RENDERER_PROCESS_CLOSING:
RendererProcessClosing(
Source<RenderProcessHost>(source).ptr());
break;
default:
NOTREACHED();
}
}
bool RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance(
int32 site_instance_id,
FrameTreeNode* node) {
RenderFrameHostMap::iterator iter =
node->render_manager()->swapped_out_hosts_.find(site_instance_id);
if (iter != node->render_manager()->swapped_out_hosts_.end()) {
RenderFrameHostImpl* swapped_out_rfh = iter->second;
if (swapped_out_rfh->render_view_host()->rvh_state() ==
RenderViewHostImpl::STATE_PENDING_SWAP_OUT) {
swapped_out_rfh->SetPendingShutdown(base::Bind(
&RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
node->render_manager()->weak_factory_.GetWeakPtr(),
site_instance_id,
swapped_out_rfh));
RFHPendingDeleteMap::iterator pending_delete_iter =
node->render_manager()->pending_delete_hosts_.find(site_instance_id);
if (pending_delete_iter ==
node->render_manager()->pending_delete_hosts_.end() ||
pending_delete_iter->second.get() != iter->second) {
node->render_manager()->pending_delete_hosts_[site_instance_id] =
linked_ptr<RenderFrameHostImpl>(swapped_out_rfh);
}
} else {
delete swapped_out_rfh;
}
node->render_manager()->swapped_out_hosts_.erase(site_instance_id);
}
return true;
}
bool RenderFrameHostManager::ShouldTransitionCrossSite() {
return
!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
!CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab);
}
bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
const NavigationEntry* current_entry,
const NavigationEntryImpl* new_entry) const {
DCHECK(new_entry);
if (new_entry->site_instance()) {
return !new_entry->site_instance()->IsRelatedSiteInstance(
render_frame_host_->GetSiteInstance());
}
BrowserContext* browser_context =
delegate_->GetControllerForRenderManager().GetBrowserContext();
const GURL& current_url = (current_entry) ?
SiteInstanceImpl::GetEffectiveURL(browser_context,
current_entry->GetURL()) :
render_frame_host_->GetSiteInstance()->GetSiteURL();
const GURL& new_url = SiteInstanceImpl::GetEffectiveURL(browser_context,
new_entry->GetURL());
if (IsRendererDebugURL(new_url))
return false;
if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
browser_context, current_url)) {
if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
browser_context, new_url)) {
return true;
}
} else {
if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
browser_context, new_url)) {
return true;
}
}
if (GetContentClient()->browser()->ShouldSwapBrowsingInstancesForNavigation(
render_frame_host_->GetSiteInstance(),
current_url, new_url)) {
return true;
}
if (current_entry &&
current_entry->IsViewSourceMode() != new_entry->IsViewSourceMode())
return true;
return false;
}
bool RenderFrameHostManager::ShouldReuseWebUI(
const NavigationEntry* current_entry,
const NavigationEntryImpl* new_entry) const {
NavigationControllerImpl& controller =
delegate_->GetControllerForRenderManager();
return current_entry && web_ui_.get() &&
(WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
controller.GetBrowserContext(), current_entry->GetURL()) ==
WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
controller.GetBrowserContext(), new_entry->GetURL()));
}
SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
const NavigationEntryImpl& entry,
SiteInstance* current_instance,
bool force_browsing_instance_swap) {
const GURL& dest_url = entry.GetURL();
NavigationControllerImpl& controller =
delegate_->GetControllerForRenderManager();
BrowserContext* browser_context = controller.GetBrowserContext();
if (entry.site_instance()) {
if (force_browsing_instance_swap) {
CHECK(!entry.site_instance()->IsRelatedSiteInstance(
render_frame_host_->GetSiteInstance()));
}
return entry.site_instance();
}
if (force_browsing_instance_swap)
return SiteInstance::CreateForURL(browser_context, dest_url);
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) &&
PageTransitionCoreTypeIs(entry.GetTransitionType(),
PAGE_TRANSITION_GENERATED)) {
return current_instance;
}
SiteInstanceImpl* current_site_instance =
static_cast<SiteInstanceImpl*>(current_instance);
if (!current_site_instance->HasSite()) {
bool use_process_per_site =
RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
if (current_site_instance->HasRelatedSiteInstance(dest_url) ||
use_process_per_site) {
return current_site_instance->GetRelatedSiteInstance(dest_url);
}
if (current_site_instance->HasWrongProcessForURL(dest_url))
return current_site_instance->GetRelatedSiteInstance(dest_url);
if (entry.IsViewSourceMode())
return SiteInstance::CreateForURL(browser_context, dest_url);
if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
browser_context, dest_url)) {
return SiteInstance::CreateForURL(browser_context, dest_url);
}
if (entry.restore_type() != NavigationEntryImpl::RESTORE_NONE)
current_site_instance->SetSite(dest_url);
return current_site_instance;
}
NavigationEntry* current_entry = controller.GetLastCommittedEntry();
if (interstitial_page_) {
current_entry = controller.GetEntryAtOffset(-1);
}
const GURL& current_url = (current_entry) ? current_entry->GetURL() :
current_instance->GetSiteURL();
if (current_entry &&
current_entry->IsViewSourceMode() != entry.IsViewSourceMode() &&
!IsRendererDebugURL(dest_url)) {
return SiteInstance::CreateForURL(browser_context, dest_url);
}
if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
!current_site_instance->HasWrongProcessForURL(dest_url)) {
return current_instance;
}
return current_instance->GetRelatedSiteInstance(dest_url);
}
RenderFrameHostImpl* RenderFrameHostManager::CreateRenderFrameHost(
SiteInstance* site_instance,
int view_routing_id,
int frame_routing_id,
bool swapped_out,
bool hidden) {
if (frame_routing_id == MSG_ROUTING_NONE)
frame_routing_id = site_instance->GetProcess()->GetNextRoutingID();
FrameTree* frame_tree = frame_tree_node_->frame_tree();
RenderViewHostImpl* render_view_host = NULL;
if (frame_tree_node_->IsMainFrame()) {
render_view_host = frame_tree->CreateRenderViewHostForMainFrame(
site_instance, view_routing_id, frame_routing_id, swapped_out, hidden);
} else {
render_view_host = frame_tree->GetRenderViewHostForSubFrame(site_instance);
if (!render_view_host) {
render_view_host = frame_tree->CreateRenderViewHostForMainFrame(
site_instance, view_routing_id, frame_routing_id, swapped_out,
hidden);
}
}
RenderFrameHostImpl* render_frame_host =
RenderFrameHostFactory::Create(render_view_host,
render_frame_delegate_,
frame_tree,
frame_tree_node_,
frame_routing_id,
swapped_out).release();
return render_frame_host;
}
int RenderFrameHostManager::CreateRenderFrame(
SiteInstance* instance,
int opener_route_id,
bool swapped_out,
bool hidden) {
CHECK(instance);
DCHECK(!swapped_out || hidden);
CHECK_NE(render_frame_host_->GetSiteInstance(), instance);
RenderFrameHostImpl* new_render_frame_host =
GetSwappedOutRenderFrameHost(instance);
FrameTreeNode* parent_node = NULL;
if (frame_tree_node_)
parent_node = frame_tree_node_->parent();
if (new_render_frame_host) {
if (!swapped_out) {
new_render_frame_host->GetProcess()->AddPendingView();
} else {
if (parent_node && cross_process_frame_connector_ &&
render_frame_host_->GetSiteInstance() == parent_node->
render_manager()->current_frame_host()->GetSiteInstance()) {
delete cross_process_frame_connector_;
cross_process_frame_connector_ = NULL;
}
}
} else {
new_render_frame_host = CreateRenderFrameHost(instance, MSG_ROUTING_NONE,
MSG_ROUTING_NONE, swapped_out,
hidden);
if (swapped_out) {
swapped_out_hosts_[instance->GetId()] = new_render_frame_host;
} else {
new_render_frame_host->GetProcess()->AddPendingView();
}
RenderViewHostImpl* render_view_host =
new_render_frame_host->render_view_host();
bool success = InitRenderView(render_view_host, opener_route_id);
if (success && frame_tree_node_->IsMainFrame()) {
render_view_host->GetView()->Hide();
} else if (!swapped_out && pending_render_frame_host_) {
CancelPending();
}
}
if (!swapped_out)
pending_render_frame_host_.reset(new_render_frame_host);
return new_render_frame_host->render_view_host()->GetRoutingID();
}
bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host,
int opener_route_id) {
if (render_view_host->IsRenderViewLive())
return true;
if (pending_web_ui() && !render_view_host->GetProcess()->IsGuest()) {
render_view_host->AllowBindings(pending_web_ui()->GetBindings());
} else {
RenderViewHostImpl* rvh_impl =
static_cast<RenderViewHostImpl*>(render_view_host);
if (!rvh_impl->IsSwappedOut()) {
CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
render_view_host->GetProcess()->GetID()));
}
}
return delegate_->CreateRenderViewForRenderManager(
render_view_host, opener_route_id, cross_process_frame_connector_);
}
void RenderFrameHostManager::CommitPending() {
bool will_focus_location_bar = delegate_->FocusLocationBarByDefault();
delegate_->CancelModalDialogsForRenderManager();
DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get()));
if (pending_web_ui_) {
web_ui_.reset(pending_web_ui_.release());
} else if (!pending_and_current_web_ui_.get()) {
web_ui_.reset();
} else {
DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get());
pending_and_current_web_ui_.reset();
}
if (!pending_render_frame_host_) {
if (will_focus_location_bar)
delegate_->SetFocusToLocationBar(false);
return;
}
bool focus_render_view = !will_focus_location_bar &&
render_frame_host_->render_view_host()->GetView() &&
render_frame_host_->render_view_host()->GetView()->HasFocus();
bool is_main_frame = frame_tree_node_->IsMainFrame();
RenderFrameHostImpl* old_render_frame_host = render_frame_host_.release();
render_frame_host_ = pending_render_frame_host_.Pass();
if (is_main_frame)
render_frame_host_->render_view_host()->AttachToFrameTree();
render_frame_host_->GetProcess()->RemovePendingView();
if (!render_frame_host_->render_view_host()->GetView()) {
delegate_->RenderProcessGoneFromRenderManager(
render_frame_host_->render_view_host());
} else if (!delegate_->IsHidden()) {
render_frame_host_->render_view_host()->GetView()->Show();
}
int32 old_site_instance_id =
old_render_frame_host->GetSiteInstance()->GetId();
if (old_render_frame_host->render_view_host()->GetView()) {
if (is_main_frame) {
old_render_frame_host->render_view_host()->GetView()->Hide();
old_render_frame_host->render_view_host()->WasSwappedOut(base::Bind(
&RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
weak_factory_.GetWeakPtr(),
old_site_instance_id,
old_render_frame_host));
} else {
old_render_frame_host->set_swapped_out(true);
}
}
delegate_->UpdateRenderViewSizeForRenderManager();
if (will_focus_location_bar) {
delegate_->SetFocusToLocationBar(false);
} else if (focus_render_view &&
render_frame_host_->render_view_host()->GetView()) {
RenderWidgetHostViewPort::FromRWHV(
render_frame_host_->render_view_host()->GetView())->Focus();
}
if (is_main_frame) {
delegate_->NotifySwappedFromRenderManager(
old_render_frame_host->render_view_host(),
render_frame_host_->render_view_host());
}
swapped_out_hosts_.erase(render_frame_host_->GetSiteInstance()->GetId());
if (old_render_frame_host->render_view_host()->IsRenderViewLive()) {
if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess))
DCHECK(old_render_frame_host->is_swapped_out() ||
!RenderViewHostImpl::IsRVHStateActive(
old_render_frame_host->render_view_host()->rvh_state()));
RenderFrameHostMap::iterator iter =
swapped_out_hosts_.find(old_site_instance_id);
if (iter != swapped_out_hosts_.end() &&
iter->second != old_render_frame_host) {
delete iter->second;
}
if (old_render_frame_host->render_view_host()->rvh_state() ==
RenderViewHostImpl::STATE_PENDING_SHUTDOWN) {
swapped_out_hosts_.erase(old_site_instance_id);
RFHPendingDeleteMap::iterator pending_delete_iter =
pending_delete_hosts_.find(old_site_instance_id);
if (pending_delete_iter == pending_delete_hosts_.end() ||
pending_delete_iter->second.get() != old_render_frame_host) {
pending_delete_hosts_[old_site_instance_id] =
linked_ptr<RenderFrameHostImpl>(old_render_frame_host);
}
} else {
swapped_out_hosts_[old_site_instance_id] = old_render_frame_host;
}
if (!static_cast<SiteInstanceImpl*>(
old_render_frame_host->GetSiteInstance())->active_view_count()) {
ShutdownRenderFrameHostsInSiteInstance(old_site_instance_id);
old_render_frame_host = NULL;
}
} else {
delete old_render_frame_host;
}
}
void RenderFrameHostManager::ShutdownRenderFrameHostsInSiteInstance(
int32 site_instance_id) {
ClearSwappedOutRFHsInSiteInstance(site_instance_id, frame_tree_node_);
scoped_ptr<RenderWidgetHostIterator> widgets(
RenderWidgetHostImpl::GetAllRenderWidgetHosts());
while (RenderWidgetHost* widget = widgets->GetNextHost()) {
if (!widget->IsRenderView())
continue;
RenderViewHostImpl* rvh =
static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget));
if (site_instance_id == rvh->GetSiteInstance()->GetId()) {
FrameTree* tree = rvh->GetDelegate()->GetFrameTree();
tree->ForEach(base::Bind(
&RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance,
site_instance_id));
}
}
}
RenderFrameHostImpl* RenderFrameHostManager::UpdateRendererStateForNavigate(
const NavigationEntryImpl& entry) {
if (cross_navigation_pending_) {
if (pending_render_frame_host_)
CancelPending();
cross_navigation_pending_ = false;
}
SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
SiteInstance* new_instance = current_instance;
bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme);
const NavigationEntry* current_entry =
delegate_->GetLastCommittedNavigationEntryForRenderManager();
bool force_swap = !is_guest_scheme &&
ShouldSwapBrowsingInstancesForNavigation(current_entry, &entry);
if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
new_instance = GetSiteInstanceForEntry(entry, current_instance, force_swap);
if (force_swap)
CHECK_NE(new_instance, current_instance);
if (new_instance != current_instance) {
DCHECK(!cross_navigation_pending_);
SetPendingWebUI(entry);
int opener_route_id = MSG_ROUTING_NONE;
if (new_instance->IsRelatedSiteInstance(current_instance)) {
opener_route_id =
delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
}
int route_id = CreateRenderFrame(new_instance, opener_route_id, false,
delegate_->IsHidden());
if (route_id == MSG_ROUTING_NONE)
return NULL;
if (!render_frame_host_->render_view_host()->IsRenderViewLive()) {
if (!cross_navigation_pending_) {
CommitPending();
return render_frame_host_.get();
} else {
NOTREACHED();
return render_frame_host_.get();
}
}
DCHECK(!pending_render_frame_host_->render_view_host()->
are_navigations_suspended());
bool is_transfer =
entry.transferred_global_request_id() != GlobalRequestID();
if (is_transfer) {
DCHECK(pending_nav_params_->global_request_id ==
entry.transferred_global_request_id());
} else {
render_frame_host_->render_view_host()->Send(new ViewMsg_Stop(
render_frame_host_->render_view_host()->GetRoutingID()));
pending_render_frame_host_->render_view_host()->SetNavigationsSuspended(
true, base::TimeTicks());
pending_render_frame_host_->render_view_host()->
SetHasPendingCrossSiteRequest(true);
}
DCHECK(!cross_navigation_pending_);
cross_navigation_pending_ = true;
if (!is_transfer)
render_frame_host_->DispatchBeforeUnload(true);
return pending_render_frame_host_.get();
}
DCHECK(!cross_navigation_pending_);
if (ShouldReuseWebUI(current_entry, &entry)) {
pending_web_ui_.reset();
pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
} else {
SetPendingWebUI(entry);
if (pending_web_ui() && !render_frame_host_->GetProcess()->IsGuest()) {
render_frame_host_->render_view_host()->AllowBindings(
pending_web_ui()->GetBindings());
}
}
if (pending_web_ui() &&
render_frame_host_->render_view_host()->IsRenderViewLive()) {
pending_web_ui()->GetController()->RenderViewReused(
render_frame_host_->render_view_host());
}
if (entry.IsViewSourceMode()) {
render_frame_host_->render_view_host()->Send(
new ViewMsg_EnableViewSourceMode(
render_frame_host_->render_view_host()->GetRoutingID()));
}
return render_frame_host_.get();
}
void RenderFrameHostManager::CancelPending() {
RenderFrameHostImpl* pending_render_frame_host =
pending_render_frame_host_.release();
RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
pending_render_frame_host->render_view_host(),
render_frame_host_->render_view_host());
pending_render_frame_host->GetProcess()->RemovePendingView();
if (IsOnSwappedOutList(pending_render_frame_host)) {
pending_render_frame_host->render_view_host()->CancelSuspendedNavigations();
pending_render_frame_host->SwapOut();
} else {
delete pending_render_frame_host;
}
pending_web_ui_.reset();
pending_and_current_web_ui_.reset();
}
void RenderFrameHostManager::RenderViewDeleted(RenderViewHost* rvh) {
if (pending_render_frame_host_ &&
rvh == pending_render_frame_host_->render_view_host()) {
NOTREACHED();
pending_render_frame_host_.reset();
}
if (!render_frame_host_)
return;
for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
iter != swapped_out_hosts_.end();
++iter) {
if (iter->second->render_view_host() == rvh) {
swapped_out_hosts_.erase(iter);
break;
}
}
}
bool RenderFrameHostManager::IsRVHOnSwappedOutList(
RenderViewHostImpl* rvh) const {
RenderFrameHostImpl* render_frame_host = GetSwappedOutRenderFrameHost(
rvh->GetSiteInstance());
if (!render_frame_host)
return false;
return IsOnSwappedOutList(render_frame_host);
}
bool RenderFrameHostManager::IsOnSwappedOutList(
RenderFrameHostImpl* rfh) const {
if (!rfh->GetSiteInstance())
return false;
RenderFrameHostMap::const_iterator iter = swapped_out_hosts_.find(
rfh->GetSiteInstance()->GetId());
if (iter == swapped_out_hosts_.end())
return false;
return iter->second == rfh;
}
RenderViewHostImpl* RenderFrameHostManager::GetSwappedOutRenderViewHost(
SiteInstance* instance) const {
RenderFrameHostImpl* render_frame_host =
GetSwappedOutRenderFrameHost(instance);
if (render_frame_host)
return render_frame_host->render_view_host();
return NULL;
}
RenderFrameHostImpl* RenderFrameHostManager::GetSwappedOutRenderFrameHost(
SiteInstance* instance) const {
RenderFrameHostMap::const_iterator iter =
swapped_out_hosts_.find(instance->GetId());
if (iter != swapped_out_hosts_.end())
return iter->second;
return NULL;
}
}