#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/stl_util.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/cross_site_transferring_request.h"
+#include "content/browser/frame_host/render_frame_proxy_host.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/renderer_host/render_widget_host_view_base.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"
const std::vector<GURL>& transfer_url_chain,
Referrer referrer,
PageTransition page_transition,
- int64 frame_id,
+ 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),
- frame_id(frame_id),
+ 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,
render_frame_delegate_(render_frame_delegate),
render_view_delegate_(render_view_delegate),
render_widget_delegate_(render_widget_delegate),
- render_frame_host_(NULL),
- pending_render_frame_host_(NULL),
interstitial_page_(NULL),
cross_process_frame_connector_(NULL),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ DCHECK(frame_tree_node_);
+}
RenderFrameHostManager::~RenderFrameHostManager() {
if (pending_render_frame_host_)
delete cross_process_frame_connector_;
// We should always have a current RenderFrameHost except in some tests.
- // TODO(creis): Now that we aren't using Shutdown, make render_frame_host_ and
- // RenderFrameHostMap use scoped_ptrs.
- RenderFrameHostImpl* render_frame_host = render_frame_host_;
- render_frame_host_ = NULL;
- if (render_frame_host)
- delete render_frame_host;
+ render_frame_host_.reset();
// Delete any swapped out RenderFrameHosts.
- for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
- iter != swapped_out_hosts_.end();
- ++iter) {
- delete iter->second;
- }
+ STLDeleteValues(&proxy_hosts_);
}
void RenderFrameHostManager::Init(BrowserContext* browser_context,
if (!site_instance)
site_instance = SiteInstance::Create(browser_context);
- // TODO(creis): Make render_frame_host_ a scoped_ptr.
- render_frame_host_ = CreateRenderFrameHost(site_instance, view_routing_id,
- frame_routing_id, false,
+ render_frame_host_ = CreateRenderFrameHost(site_instance,
+ view_routing_id,
+ frame_routing_id,
+ false,
delegate_->IsHidden());
// Keep track of renderer processes as they start to shut down or are
const NavigationEntryImpl& entry) {
TRACE_EVENT0("browser", "RenderFrameHostManager:Navigate");
// Create a pending RenderFrameHost to use for the navigation.
- RenderFrameHostImpl* dest_render_frame_host =
- UpdateRendererStateForNavigate(entry);
+ RenderFrameHostImpl* dest_render_frame_host = UpdateStateForNavigate(entry);
if (!dest_render_frame_host)
return NULL; // We weren't able to create a pending render frame host.
if (!dest_render_frame_host->render_view_host()->IsRenderViewLive()) {
// Recreate the opener chain.
int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
- dest_render_frame_host->render_view_host()->GetSiteInstance());
+ dest_render_frame_host->GetSiteInstance());
if (!InitRenderView(dest_render_frame_host->render_view_host(),
opener_route_id))
return NULL;
return false;
}
-// TODO(creis): Remove this in favor of SwappedOutFrame.
-void RenderFrameHostManager::SwappedOut(RenderViewHost* render_view_host) {
- // Make sure this is from our current RVH, and that we have a pending
- // navigation from OnCrossSiteResponse. (There may be no pending navigation
- // for data URLs that don't make network requests, for example.) If not,
- // just return early and ignore.
- if (render_view_host != render_frame_host_->render_view_host() ||
- !pending_nav_params_.get()) {
- pending_nav_params_.reset();
- return;
- }
+void RenderFrameHostManager::OnBeforeUnloadACK(
+ bool for_cross_site_transition,
+ bool proceed,
+ const base::TimeTicks& proceed_time) {
+ if (for_cross_site_transition) {
+ // Ignore if we're not in a cross-site navigation.
+ if (!cross_navigation_pending_)
+ return;
- // Now that the unload handler has run, we need to either initiate the
- // pending transfer (if there is one) or resume the paused response (if not).
- // TODO(creis): The blank swapped out page is visible during this time, but
- // we can shorten this by delivering the response directly, rather than
- // forcing an identical request to be made.
- if (pending_nav_params_->cross_site_transferring_request) {
- // Treat the last URL in the chain as the destination and the remainder as
- // the redirect chain.
- 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();
+ if (proceed) {
+ // Ok to unload the current page, so proceed with the cross-site
+ // navigation. Note that if navigations are not currently suspended, it
+ // might be because the renderer was deemed unresponsive and this call was
+ // already made by ShouldCloseTabOnUnresponsiveRenderer. In that case, it
+ // is ok to do nothing here.
+ 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 {
+ // Current page says to cancel.
+ CancelPending();
+ cross_navigation_pending_ = false;
+ }
+ } else {
+ // Non-cross site transition means closing the entire tab.
+ bool proceed_to_fire_unload;
+ delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
+ &proceed_to_fire_unload);
- // We don't know whether the original request had |user_action| set to true.
- // However, since we force the navigation to be in the current tab, it
- // doesn't matter.
- render_view_host->GetDelegate()->RequestTransferURL(
- transfer_url,
- pending_nav_params_->transfer_url_chain,
- pending_nav_params_->referrer,
- pending_nav_params_->page_transition,
- CURRENT_TAB,
- pending_nav_params_->frame_id,
- 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);
+ if (proceed_to_fire_unload) {
+ // If we're about to close the tab and there's a pending RFH, cancel it.
+ // Otherwise, if the navigation in the pending RFH completes before the
+ // close in the current RFH, we'll lose the tab close.
+ if (pending_render_frame_host_) {
+ CancelPending();
+ cross_navigation_pending_ = false;
+ }
+
+ // This is not a cross-site navigation, the tab is being closed.
+ render_frame_host_->render_view_host()->ClosePage();
+ }
}
- pending_nav_params_.reset();
}
-void RenderFrameHostManager::SwappedOutFrame(
+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) {
+ // This should be called either when the pending RFH is ready to commit or
+ // when we realize that the current RFH's request requires a transfer.
+ DCHECK(pending_render_frame_host == pending_render_frame_host_ ||
+ pending_render_frame_host == render_frame_host_);
+
+ // TODO(creis): Eventually we will want to check all navigation responses
+ // here, but currently we pass information for a transfer if
+ // ShouldSwapProcessesForRedirect returned true in the network stack.
+ // In that case, we should set up a transfer after the unload handler runs.
+ // If |cross_site_transferring_request| is NULL, we will just run the unload
+ // handler and resume.
+ 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));
+
+ // Run the unload handler of the current page.
+ SwapOutOldPage();
+}
+
+void RenderFrameHostManager::SwappedOut(
RenderFrameHostImpl* render_frame_host) {
// Make sure this is from our current RFH, and that we have a pending
// navigation from OnCrossSiteResponse. (There may be no pending navigation
return;
}
- // Sanity check that this is for the correct frame.
- DCHECK_EQ(frame_tree_node_->frame_id(), pending_nav_params_->frame_id);
-
// Now that the unload handler has run, we need to either initiate the
// pending transfer (if there is one) or resume the paused response (if not).
// TODO(creis): The blank swapped out page is visible during this time, but
// we can shorten this by delivering the response directly, rather than
// forcing an identical request to be made.
if (pending_nav_params_->cross_site_transferring_request) {
+ // Sanity check that the params are for the correct frame and process.
+ // These should match the RenderFrameHost that made the request.
+ // If it started as a cross-process navigation via OpenURL, this is the
+ // pending one. If it wasn't cross-process until the transfer, this is the
+ // current one.
+ 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);
+
// Treat the last URL in the chain as the destination and the remainder as
// the redirect chain.
CHECK(pending_nav_params_->transfer_url_chain.size());
// We don't know whether the original request had |user_action| set to true.
// However, since we force the navigation to be in the current tab, it
// doesn't matter.
- // TODO(creis): Move RequestTransferURL to RenderFrameHost's navigator.
- render_frame_host->render_view_host()->GetDelegate()->RequestTransferURL(
+ 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_->frame_id,
pending_nav_params_->global_request_id,
- false,
+ pending_nav_params_->should_replace_current_entry,
true);
} else if (pending_render_frame_host_) {
RenderProcessHostImpl* pending_process =
pending_nav_params_.reset();
}
-// TODO(creis): This should take in a RenderFrameHost.
-void RenderFrameHostManager::DidNavigateMainFrame(
- RenderViewHost* render_view_host) {
+void RenderFrameHostManager::DidNavigateFrame(
+ RenderFrameHostImpl* render_frame_host) {
if (!cross_navigation_pending_) {
DCHECK(!pending_render_frame_host_);
// We should only hear this from our current renderer.
- DCHECK(render_view_host == render_frame_host_->render_view_host());
+ DCHECK_EQ(render_frame_host_, render_frame_host);
// Even when there is no pending RVH, there may be a pending Web UI.
if (pending_web_ui())
return;
}
- if (render_view_host == pending_render_frame_host_->render_view_host()) {
+ if (render_frame_host == pending_render_frame_host_) {
// The pending cross-site navigation completed, so show the renderer.
// If it committed without sending network requests (e.g., data URLs),
// then we still need to swap out the old RFH first and run its unload
- // handler. OK for that to happen in the background.
+ // handler, only if it hasn't happened yet. OK for that to happen in the
+ // background.
if (pending_render_frame_host_->render_view_host()->
- HasPendingCrossSiteRequest())
+ HasPendingCrossSiteRequest() &&
+ pending_render_frame_host_->render_view_host()->rvh_state() ==
+ RenderViewHostImpl::STATE_DEFAULT) {
SwapOutOldPage();
+ }
CommitPending();
cross_navigation_pending_ = false;
- } else if (render_view_host == render_frame_host_->render_view_host()) {
+ } else if (render_frame_host == render_frame_host_) {
// A navigation in the original page has taken place. Cancel the pending
// one.
CancelPending();
// TODO(creis): Take in RenderFrameHost instead, since frames can have openers.
void RenderFrameHostManager::DidDisownOpener(RenderViewHost* render_view_host) {
// Notify all swapped out hosts, including the pending RVH.
- for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
- iter != swapped_out_hosts_.end();
+ for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
+ iter != proxy_hosts_.end();
++iter) {
- DCHECK_NE(iter->second->render_view_host()->GetSiteInstance(),
- current_host()->GetSiteInstance());
+ DCHECK_NE(iter->second->GetSiteInstance(),
+ current_frame_host()->GetSiteInstance());
iter->second->render_view_host()->DisownOpener();
}
}
// swap them back in while the process is exiting. Start by finding them,
// since there could be more than one.
std::list<int> ids_to_remove;
- for (RenderFrameHostMap::iterator iter = swapped_out_hosts_.begin();
- iter != swapped_out_hosts_.end();
+ for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
+ iter != proxy_hosts_.end();
++iter) {
if (iter->second->GetProcess() == render_process_host)
ids_to_remove.push_back(iter->first);
// Now delete them.
while (!ids_to_remove.empty()) {
- delete swapped_out_hosts_[ids_to_remove.back()];
- swapped_out_hosts_.erase(ids_to_remove.back());
+ delete proxy_hosts_[ids_to_remove.back()];
+ proxy_hosts_.erase(ids_to_remove.back());
ids_to_remove.pop_back();
}
}
-void RenderFrameHostManager::ShouldClosePage(
- bool for_cross_site_transition,
- bool proceed,
- const base::TimeTicks& proceed_time) {
- if (for_cross_site_transition) {
- // Ignore if we're not in a cross-site navigation.
- if (!cross_navigation_pending_)
- return;
-
- if (proceed) {
- // Ok to unload the current page, so proceed with the cross-site
- // navigation. Note that if navigations are not currently suspended, it
- // might be because the renderer was deemed unresponsive and this call was
- // already made by ShouldCloseTabOnUnresponsiveRenderer. In that case, it
- // is ok to do nothing here.
- 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 {
- // Current page says to cancel.
- CancelPending();
- cross_navigation_pending_ = false;
- }
- } else {
- // Non-cross site transition means closing the entire tab.
- bool proceed_to_fire_unload;
- delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time,
- &proceed_to_fire_unload);
-
- if (proceed_to_fire_unload) {
- // If we're about to close the tab and there's a pending RFH, cancel it.
- // Otherwise, if the navigation in the pending RFH completes before the
- // close in the current RFH, we'll lose the tab close.
- if (pending_render_frame_host_) {
- CancelPending();
- cross_navigation_pending_ = false;
- }
-
- // This is not a cross-site navigation, the tab is being closed.
- render_frame_host_->render_view_host()->ClosePage();
- }
- }
-}
-
-// TODO(creis): Take in a RenderFrameHost from CSRH.
-void RenderFrameHostManager::OnCrossSiteResponse(
- RenderViewHost* pending_render_view_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,
- int64 frame_id,
- bool should_replace_current_entry) {
- // This should be called either when the pending RVH is ready to commit or
- // when we realize that the current RVH's request requires a transfer.
- DCHECK(pending_render_view_host == render_frame_host_->render_view_host() ||
- pending_render_view_host ==
- pending_render_frame_host_->render_view_host());
-
- // TODO(creis): Eventually we will want to check all navigation responses
- // here, but currently we pass information for a transfer if
- // ShouldSwapProcessesForRedirect returned true in the network stack.
- // In that case, we should set up a transfer after the unload handler runs.
- // If |cross_site_transferring_request| is NULL, we will just run the unload
- // handler and resume.
- pending_nav_params_.reset(new PendingNavigationParams(
- global_request_id, cross_site_transferring_request.Pass(),
- transfer_url_chain, referrer, page_transition, frame_id,
- should_replace_current_entry));
-
- // Run the unload handler of the current page.
- SwapOutOldPage();
-}
-
void RenderFrameHostManager::SwapOutOldPage() {
// Should only see this while we have a pending renderer or transfer.
CHECK(cross_navigation_pending_ || pending_nav_params_.get());
// Tell the renderer to suppress any further modal dialogs so that we can swap
// it out. This must be done before canceling any current dialog, in case
// there is a loop creating additional dialogs.
+ // TODO(creis): Handle modal dialogs in subframe processes.
render_frame_host_->render_view_host()->SuppressDialogsUntilSwapOut();
// Now close any modal dialogs that would prevent us from swapping out. This
// no longer on the stack when we send the SwapOut message.
delegate_->CancelModalDialogsForRenderManager();
- // Tell the old renderer it is being swapped out. This will fire the unload
- // handler (without firing the beforeunload handler a second time). When the
- // unload handler finishes and the navigation completes, we will send a
- // message to the ResourceDispatcherHost, allowing the pending RVH's response
- // to resume.
- // Note: This must be done on the RFH or else we'll swap out the top-level
- // page when subframes navigate.
- if (frame_tree_node_->IsMainFrame())
- render_frame_host_->render_view_host()->SwapOut();
- else
- render_frame_host_->SwapOut();
+ if (!frame_tree_node_->IsMainFrame()) {
+ // The RenderFrameHost being swapped out becomes the proxy for this
+ // frame in its parent's process. CrossProcessFrameConnector
+ // initialization only needs to happen on an initial cross-process
+ // navigation, when the RenderFrame leaves the same process as its parent.
+ // The same CrossProcessFrameConnector is used for subsequent cross-
+ // process navigations, but it will be destroyed if the Frame is
+ // navigated back to the same site instance as its parent.
+ // TODO(kenrb): This will change when RenderFrameProxyHost is created.
+ if (!cross_process_frame_connector_) {
+ cross_process_frame_connector_ =
+ new CrossProcessFrameConnector(render_frame_host_.get());
+ }
+ }
+
+ // Tell the old frame it is being swapped out. This will fire the unload
+ // handler in the background (without firing the beforeunload handler a second
+ // time). When the navigation completes, we will send a message to the
+ // ResourceDispatcherHost, allowing the pending RVH's response to resume.
+ render_frame_host_->SwapOut();
// ResourceDispatcherHost has told us to run the onunload handler, which
// means it is not a download or unsafe page, and we are going to perform the
}
}
-bool RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance(
+bool RenderFrameHostManager::ClearProxiesInSiteInstance(
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;
+ RenderFrameProxyHostMap::iterator iter =
+ node->render_manager()->proxy_hosts_.find(site_instance_id);
+ if (iter != node->render_manager()->proxy_hosts_.end()) {
+ RenderFrameProxyHost* proxy = iter->second;
// If the RVH is pending swap out, it needs to switch state to
// pending shutdown. Otherwise it is deleted.
- if (swapped_out_rfh->render_view_host()->rvh_state() ==
+ if (proxy->render_view_host()->rvh_state() ==
RenderViewHostImpl::STATE_PENDING_SWAP_OUT) {
+ scoped_ptr<RenderFrameHostImpl> swapped_out_rfh = proxy->PassFrameHost();
+
swapped_out_rfh->SetPendingShutdown(base::Bind(
&RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
node->render_manager()->weak_factory_.GetWeakPtr(),
site_instance_id,
- swapped_out_rfh));
+ swapped_out_rfh.get()));
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) {
+ pending_delete_iter->second.get() != swapped_out_rfh) {
node->render_manager()->pending_delete_hosts_[site_instance_id] =
- linked_ptr<RenderFrameHostImpl>(swapped_out_rfh);
+ linked_ptr<RenderFrameHostImpl>(swapped_out_rfh.release());
}
} else {
- delete swapped_out_rfh;
+ delete proxy;
}
- node->render_manager()->swapped_out_hosts_.erase(site_instance_id);
+ node->render_manager()->proxy_hosts_.erase(site_instance_id);
}
return true;
const NavigationEntryImpl* new_entry) const {
DCHECK(new_entry);
- // If new_entry already has a SiteInstance, assume it is correct and use it.
- if (new_entry->site_instance())
- return false;
+ // If new_entry already has a SiteInstance, assume it is correct. We only
+ // need to force a swap if it is in a different BrowsingInstance.
+ if (new_entry->site_instance()) {
+ return !new_entry->site_instance()->IsRelatedSiteInstance(
+ render_frame_host_->GetSiteInstance());
+ }
// Check for reasons to swap processes even if we are in a process model that
// doesn't usually swap (e.g., process-per-tab). Any time we return true,
const GURL& current_url = (current_entry) ?
SiteInstanceImpl::GetEffectiveURL(browser_context,
current_entry->GetURL()) :
- render_frame_host_->render_view_host()->GetSiteInstance()->GetSiteURL();
+ render_frame_host_->GetSiteInstance()->GetSiteURL();
const GURL& new_url = SiteInstanceImpl::GetEffectiveURL(browser_context,
new_entry->GetURL());
// Check with the content client as well. Important to pass current_url here,
// which uses the SiteInstance's site if there is no current_entry.
if (GetContentClient()->browser()->ShouldSwapBrowsingInstancesForNavigation(
- render_frame_host_->render_view_host()->GetSiteInstance(),
+ render_frame_host_->GetSiteInstance(),
current_url, new_url)) {
return true;
}
delegate_->GetControllerForRenderManager();
BrowserContext* browser_context = controller.GetBrowserContext();
+ // If the entry has an instance already we should use it.
+ if (entry.site_instance()) {
+ // If we are forcing a swap, this should be in a different BrowsingInstance.
+ if (force_browsing_instance_swap) {
+ CHECK(!entry.site_instance()->IsRelatedSiteInstance(
+ render_frame_host_->GetSiteInstance()));
+ }
+ return entry.site_instance();
+ }
+
// If a swap is required, we need to force the SiteInstance AND
// BrowsingInstance to be different ones, using CreateForURL.
- if (force_browsing_instance_swap) {
- // We shouldn't be forcing a swap if an entry already has a SiteInstance.
- CHECK(!entry.site_instance());
+ if (force_browsing_instance_swap)
return SiteInstance::CreateForURL(browser_context, dest_url);
- }
-
- // If the entry has an instance already we should use it.
- if (entry.site_instance())
- return entry.site_instance();
// (UGLY) HEURISTIC, process-per-site only:
//
return current_instance->GetRelatedSiteInstance(dest_url);
}
-RenderFrameHostImpl* RenderFrameHostManager::CreateRenderFrameHost(
+scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
SiteInstance* site_instance,
int view_routing_id,
int frame_routing_id,
}
}
- // TODO(creis): Make render_frame_host a scoped_ptr.
// TODO(creis): Pass hidden to RFH.
- 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;
+ scoped_ptr<RenderFrameHostImpl> render_frame_host =
+ make_scoped_ptr(RenderFrameHostFactory::Create(render_view_host,
+ render_frame_delegate_,
+ frame_tree,
+ frame_tree_node_,
+ frame_routing_id,
+ swapped_out).release());
+ return render_frame_host.Pass();
}
int RenderFrameHostManager::CreateRenderFrame(
CHECK(instance);
DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
+ scoped_ptr<RenderFrameHostImpl> new_render_frame_host;
+ int routing_id = MSG_ROUTING_NONE;
+
// We are creating a pending or swapped out RFH here. We should never create
// it in the same SiteInstance as our current RFH.
- CHECK_NE(render_frame_host_->render_view_host()->GetSiteInstance(), instance);
+ CHECK_NE(render_frame_host_->GetSiteInstance(), instance);
// Check if we've already created an RFH for this SiteInstance. If so, try
// to re-use the existing one, which has already been initialized. We'll
// remove it from the list of swapped out hosts if it commits.
- RenderFrameHostImpl* new_render_frame_host =
- GetSwappedOutRenderFrameHost(instance);
+ RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
- FrameTreeNode* parent_node = NULL;
- if (frame_tree_node_)
- parent_node = frame_tree_node_->parent();
+ FrameTreeNode* parent_node = frame_tree_node_->parent();
- if (new_render_frame_host) {
+ if (proxy) {
+ routing_id = proxy->render_view_host()->GetRoutingID();
+ // Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost.
// Prevent the process from exiting while we're trying to use it.
if (!swapped_out) {
+ new_render_frame_host = proxy->PassFrameHost();
new_render_frame_host->GetProcess()->AddPendingView();
+
+ proxy_hosts_.erase(instance->GetId());
+ delete proxy;
} else {
// Detect if this is a cross-process child frame that is navigating
// back to the same SiteInstance as its parent.
}
} else {
// Create a new RenderFrameHost if we don't find an existing one.
- // TODO(creis): Make new_render_frame_host a scoped_ptr.
- new_render_frame_host = CreateRenderFrameHost(instance, MSG_ROUTING_NONE,
- MSG_ROUTING_NONE, swapped_out,
- hidden);
- if (parent_node && !cross_process_frame_connector_) {
- // The proxy RenderFrameHost to the parent process is either the current
- // RenderFrameHost, or it has been added to the swapped out list.
- // TODO(kenrb): This will change when RenderFrameProxyHost is created.
- RenderFrameHostImpl* proxy_to_parent = render_frame_host_;
- if (render_frame_host_->render_view_host()->GetSiteInstance() !=
- parent_node->render_manager()->current_host()->GetSiteInstance()) {
- GetSwappedOutRenderFrameHost(
- parent_node->render_manager()->current_host()->GetSiteInstance());
- }
- CHECK(proxy_to_parent);
- cross_process_frame_connector_ =
- new CrossProcessFrameConnector(proxy_to_parent);
- }
+ new_render_frame_host = CreateRenderFrameHost(
+ instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, swapped_out, hidden);
+ RenderViewHostImpl* render_view_host =
+ new_render_frame_host->render_view_host();
- // If the new RFH is swapped out already, store it. Otherwise prevent the
- // process from exiting while we're trying to navigate in it.
- if (swapped_out) {
- swapped_out_hosts_[instance->GetId()] = new_render_frame_host;
- } else {
+ // Prevent the process from exiting while we're trying to navigate in it.
+ // Otherwise, if the new RFH is swapped out already, store it.
+ if (!swapped_out) {
new_render_frame_host->GetProcess()->AddPendingView();
+ } else {
+ proxy_hosts_[instance->GetId()] = new RenderFrameProxyHost(
+ new_render_frame_host.Pass());
}
- 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()) {
// Don't show the main frame's view until we get a DidNavigate from it.
} else if (!swapped_out && pending_render_frame_host_) {
CancelPending();
}
+ routing_id = render_view_host->GetRoutingID();
}
// Use this as our new pending RFH if it isn't swapped out.
if (!swapped_out)
- pending_render_frame_host_ = new_render_frame_host;
+ pending_render_frame_host_ = new_render_frame_host.Pass();
- return new_render_frame_host->render_view_host()->GetRoutingID();
+ return routing_id;
}
bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host,
// Swap in the pending frame and make it active. Also ensure the FrameTree
// stays in sync.
- RenderFrameHostImpl* old_render_frame_host = render_frame_host_;
- render_frame_host_ = pending_render_frame_host_;
- pending_render_frame_host_ = NULL;
+ scoped_ptr<RenderFrameHostImpl> old_render_frame_host =
+ render_frame_host_.Pass();
+ render_frame_host_ = pending_render_frame_host_.Pass();
if (is_main_frame)
render_frame_host_->render_view_host()->AttachToFrameTree();
// If the old view is live and top-level, hide it now that the new one is
// visible.
int32 old_site_instance_id =
- old_render_frame_host->render_view_host()->GetSiteInstance()->GetId();
+ 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();
&RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
weak_factory_.GetWeakPtr(),
old_site_instance_id,
- old_render_frame_host));
+ old_render_frame_host.get()));
} else {
// TODO(creis): We'll need to set this back to false if we navigate back.
old_render_frame_host->set_swapped_out(true);
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();
+ render_frame_host_->render_view_host()->GetView()->Focus();
}
// Notify that we've swapped RenderFrameHosts. We do this before shutting down
render_frame_host_->render_view_host());
}
- // If the pending frame was on the swapped out list, we can remove it.
- swapped_out_hosts_.erase(render_frame_host_->render_view_host()->
- GetSiteInstance()->GetId());
-
- if (old_render_frame_host->render_view_host()->IsRenderViewLive()) {
- // If the old RFH is live, we are swapping it out and should keep track of
- // it in case we navigate back to it, or it is waiting for the unload event
- // to execute in the background.
- // TODO(creis): Swap out the subframe in --site-per-process.
- 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()));
- // Temp fix for http://crbug.com/90867 until we do a better cleanup to make
- // sure we don't get different rvh instances for the same site instance
- // in the same rvhmgr.
- // TODO(creis): Clean this up.
- RenderFrameHostMap::iterator iter =
- swapped_out_hosts_.find(old_site_instance_id);
- if (iter != swapped_out_hosts_.end() &&
- iter->second != old_render_frame_host) {
- // Delete the RFH that will be replaced in the map to avoid a leak.
- delete iter->second;
- }
- // If the RenderViewHost backing the RenderFrameHost is pending shutdown,
- // the RenderFrameHost should be put in the map of RenderFrameHosts pending
- // shutdown. Otherwise, it is stored in the map of swapped out
- // RenderFrameHosts.
- 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 the old RFH is not live, just return as there is no work to do.
+ if (!old_render_frame_host->render_view_host()->IsRenderViewLive()) {
+ return;
+ }
+ // If the old RFH is live, we are swapping it out and should keep track of
+ // it in case we navigate back to it, or it is waiting for the unload event
+ // to execute in the background.
+ // TODO(creis): Swap out the subframe in --site-per-process.
+ 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()));
+ // Temp fix for http://crbug.com/90867 until we do a better cleanup to make
+ // sure we don't get different rvh instances for the same site instance
+ // in the same rvhmgr.
+ // TODO(creis): Clean this up.
+ RenderFrameProxyHostMap::iterator iter =
+ proxy_hosts_.find(old_site_instance_id);
+ if (iter != proxy_hosts_.end() &&
+ iter->second->render_frame_host() != old_render_frame_host) {
+ // Delete the proxy that will be replaced in the map to avoid a leak.
+ delete iter->second;
+ }
+
+ // If the RenderViewHost backing the RenderFrameHost is pending shutdown,
+ // the RenderFrameHost should be put in the map of RenderFrameHosts pending
+ // shutdown. Otherwise, it is stored in the map of proxy hosts.
+ if (old_render_frame_host->render_view_host()->rvh_state() ==
+ RenderViewHostImpl::STATE_PENDING_SHUTDOWN) {
+ proxy_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.release());
+ }
+ } else {
// If there are no active views in this SiteInstance, it means that
// this RFH was the last active one in the SiteInstance. Now that we
// know that all RFHs are swapped out, we can delete all the RFHs and RVHs
// in this SiteInstance. We do this after ensuring the RFH is on the
// swapped out list to simplify the deletion.
if (!static_cast<SiteInstanceImpl*>(
- old_render_frame_host->render_view_host()->GetSiteInstance())->
- active_view_count()) {
+ old_render_frame_host->GetSiteInstance())->active_view_count()) {
+ old_render_frame_host.reset();
ShutdownRenderFrameHostsInSiteInstance(old_site_instance_id);
- // This is deleted while cleaning up the SiteInstance's views.
- old_render_frame_host = NULL;
+ } else {
+ proxy_hosts_[old_site_instance_id] = new RenderFrameProxyHost(
+ old_render_frame_host.Pass());
}
- } else {
- delete old_render_frame_host;
}
}
void RenderFrameHostManager::ShutdownRenderFrameHostsInSiteInstance(
int32 site_instance_id) {
// First remove any swapped out RFH for this SiteInstance from our own list.
- ClearSwappedOutRFHsInSiteInstance(site_instance_id, frame_tree_node_);
+ ClearProxiesInSiteInstance(site_instance_id, frame_tree_node_);
// Use the safe RenderWidgetHost iterator for now to find all RenderViewHosts
// in the SiteInstance, then tell their respective FrameTrees to remove all
- // swapped out RenderFrameHosts corresponding to them.
+ // RenderFrameProxyHosts corresponding to them.
// TODO(creis): Replace this with a RenderFrameHostIterator that protects
// against use-after-frees if a later element is deleted before getting to it.
scoped_ptr<RenderWidgetHostIterator> widgets(
// |rvh| to Shutdown.
FrameTree* tree = rvh->GetDelegate()->GetFrameTree();
tree->ForEach(base::Bind(
- &RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance,
+ &RenderFrameHostManager::ClearProxiesInSiteInstance,
site_instance_id));
}
}
}
-RenderFrameHostImpl* RenderFrameHostManager::UpdateRendererStateForNavigate(
+RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
const NavigationEntryImpl& entry) {
// If we are currently navigating cross-process, we want to get back to normal
// and then navigate as usual.
// render_frame_host_'s SiteInstance and new_instance will not be deleted
// before the end of this method, so we don't have to worry about their ref
// counts dropping to zero.
- SiteInstance* current_instance =
- render_frame_host_->render_view_host()->GetSiteInstance();
+ SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
SiteInstance* new_instance = current_instance;
// We do not currently swap processes for navigations in webview tag guests.
// cross-navigating (Note that we don't care about on{before}unload
// handlers if the current RFH isn't live.)
CommitPending();
- return render_frame_host_;
+ return render_frame_host_.get();
} else {
NOTREACHED();
- return render_frame_host_;
+ return render_frame_host_.get();
}
}
// Otherwise, it's safe to treat this as a pending cross-site transition.
// Unless we are transferring an existing request, we should now
// tell the old render view to run its beforeunload handler, since it
// doesn't otherwise know that the cross-site request is happening. This
- // will trigger a call to ShouldClosePage with the reply.
+ // will trigger a call to OnBeforeUnloadACK with the reply.
if (!is_transfer)
- render_frame_host_->render_view_host()->FirePageBeforeUnload(true);
+ render_frame_host_->DispatchBeforeUnload(true);
- return pending_render_frame_host_;
+ return pending_render_frame_host_.get();
}
// Otherwise the same SiteInstance can be used. Navigate render_frame_host_.
render_frame_host_->render_view_host()->GetRoutingID()));
}
- return render_frame_host_;
+ return render_frame_host_.get();
}
void RenderFrameHostManager::CancelPending() {
- RenderFrameHostImpl* pending_render_frame_host = pending_render_frame_host_;
- pending_render_frame_host_ = NULL;
+ scoped_ptr<RenderFrameHostImpl> pending_render_frame_host =
+ pending_render_frame_host_.Pass();
RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
pending_render_frame_host->render_view_host(),
// We no longer need to prevent the process from exiting.
pending_render_frame_host->GetProcess()->RemovePendingView();
- // The pending RFH may already be on the swapped out list if we started to
- // swap it back in and then canceled. If so, make sure it gets swapped out
- // again. If it's not on the swapped out list (e.g., aborting a pending
- // load), then it's safe to shut down.
- if (IsOnSwappedOutList(pending_render_frame_host)) {
+ // If the SiteInstance for the pending RFH is being used by others, don't
+ // delete the RFH, just swap it out and it can be reused at a later point.
+ SiteInstanceImpl* site_instance = static_cast<SiteInstanceImpl*>(
+ pending_render_frame_host->GetSiteInstance());
+ if (site_instance->active_view_count() > 1) {
// Any currently suspended navigations are no longer needed.
pending_render_frame_host->render_view_host()->CancelSuspendedNavigations();
- // TODO(creis): We need to swap out the RFH.
- pending_render_frame_host->render_view_host()->SwapOut();
+ pending_render_frame_host->SwapOut();
+
+ proxy_hosts_[site_instance->GetId()] = new RenderFrameProxyHost(
+ pending_render_frame_host.Pass());
} else {
- // We won't be coming back, so shut this one down.
- delete pending_render_frame_host;
+ // We won't be coming back, so delete this one.
+ pending_render_frame_host.reset();
}
pending_web_ui_.reset();
pending_and_current_web_ui_.reset();
}
-void RenderFrameHostManager::RenderViewDeleted(RenderViewHost* rvh) {
- // We are doing this in order to work around and to track a crasher
- // (http://crbug.com/23411) where it seems that pending_render_frame_host_ is
- // deleted (not sure from where) but not NULLed.
- if (pending_render_frame_host_ &&
- rvh == pending_render_frame_host_->render_view_host()) {
- // If you hit this NOTREACHED, please report it in the following bug
- // http://crbug.com/23411 Make sure to include what you were doing when it
- // happened (navigating to a new page, closing a tab...) and if you can
- // reproduce.
- NOTREACHED();
- pending_render_frame_host_ = NULL;
- }
-
- // Make sure deleted RVHs are not kept in the swapped out list while we are
- // still alive. (If render_frame_host_ is null, we're already being deleted.)
- if (!render_frame_host_)
- return;
-
- // We can't look it up by SiteInstance ID, which may no longer be valid.
- 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(
+ RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(
rvh->GetSiteInstance());
- if (!render_frame_host)
+ if (!proxy)
return false;
- return IsOnSwappedOutList(render_frame_host);
+ return IsOnSwappedOutList(proxy->render_frame_host());
}
bool RenderFrameHostManager::IsOnSwappedOutList(
RenderFrameHostImpl* rfh) const {
- if (!rfh->render_view_host()->GetSiteInstance())
+ if (!rfh->GetSiteInstance())
return false;
- RenderFrameHostMap::const_iterator iter = swapped_out_hosts_.find(
- rfh->render_view_host()->GetSiteInstance()->GetId());
- if (iter == swapped_out_hosts_.end())
+ RenderFrameProxyHostMap::const_iterator iter = proxy_hosts_.find(
+ rfh->GetSiteInstance()->GetId());
+ if (iter == proxy_hosts_.end())
return false;
- return iter->second == rfh;
+ return iter->second->render_frame_host() == rfh;
}
RenderViewHostImpl* RenderFrameHostManager::GetSwappedOutRenderViewHost(
SiteInstance* instance) const {
- RenderFrameHostImpl* render_frame_host =
- GetSwappedOutRenderFrameHost(instance);
- if (render_frame_host)
- return render_frame_host->render_view_host();
+ RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
+ if (proxy)
+ return proxy->render_view_host();
return NULL;
}
-RenderFrameHostImpl* RenderFrameHostManager::GetSwappedOutRenderFrameHost(
+RenderFrameProxyHost* RenderFrameHostManager::GetRenderFrameProxyHost(
SiteInstance* instance) const {
- RenderFrameHostMap::const_iterator iter =
- swapped_out_hosts_.find(instance->GetId());
- if (iter != swapped_out_hosts_.end())
+ RenderFrameProxyHostMap::const_iterator iter =
+ proxy_hosts_.find(instance->GetId());
+ if (iter != proxy_hosts_.end())
return iter->second;
return NULL;