summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-14 20:28:03 +0000
committernasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-14 20:28:03 +0000
commit539c1022ad2837b2171d510252afa575f89d9dcb (patch)
treeac63585ed5471cbcd44180b75e4a6f4a1ce380ea
parentd1222a67905f9505110150dfc8b5ba0b59f8928b (diff)
downloadchromium_src-539c1022ad2837b2171d510252afa575f89d9dcb.zip
chromium_src-539c1022ad2837b2171d510252afa575f89d9dcb.tar.gz
chromium_src-539c1022ad2837b2171d510252afa575f89d9dcb.tar.bz2
Introduce RenderFrameProxyHost object and use it in RFHM.
This is a reland of previous attempt. Patch Set 1 is a copy of the original CL: https://codereview.chromium.org/217163007/ This is the first CL in a series to create RenderFrameProxy(Host) infrastructure. Before the Blink codebase is ready to transform local and remote frames, the proxy objects will keep internally the existing RF/RFH in swapped out state. This CL creates the browser side proxy object and wraps the swapped out RFH. BUG=357747 R=creis@chromium.org Review URL: https://codereview.chromium.org/235573009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@263720 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/frame_host/render_frame_host_manager.cc263
-rw-r--r--content/browser/frame_host/render_frame_host_manager.h29
-rw-r--r--content/browser/frame_host/render_frame_host_manager_unittest.cc81
-rw-r--r--content/browser/frame_host/render_frame_proxy_host.cc19
-rw-r--r--content/browser/frame_host/render_frame_proxy_host.h88
-rw-r--r--content/content_browser.gypi2
6 files changed, 342 insertions, 140 deletions
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index b9c5be3..2dfc221 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -20,6 +20,7 @@
#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/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"
@@ -89,11 +90,9 @@ RenderFrameHostManager::~RenderFrameHostManager() {
// We should always have a current RenderFrameHost except in some tests.
render_frame_host_.reset();
- // TODO(creis): Now that we aren't using Shutdown, make RenderFrameHostMap
- // use scoped_ptrs.
// Delete any swapped out RenderFrameHosts.
- 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) {
delete iter->second;
}
@@ -109,9 +108,11 @@ void RenderFrameHostManager::Init(BrowserContext* browser_context,
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()));
+ 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
// crashed/killed.
@@ -447,8 +448,8 @@ void RenderFrameHostManager::DidNavigateFrame(
// 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->GetSiteInstance(),
current_frame_host()->GetSiteInstance());
@@ -462,8 +463,8 @@ void RenderFrameHostManager::RendererProcessClosing(
// 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);
@@ -471,8 +472,8 @@ void RenderFrameHostManager::RendererProcessClosing(
// 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();
}
}
@@ -548,34 +549,36 @@ void RenderFrameHostManager::Observe(
}
}
-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;
@@ -833,7 +836,7 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
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,
@@ -862,16 +865,15 @@ RenderFrameHostImpl* RenderFrameHostManager::CreateRenderFrameHost(
}
}
- // 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(
@@ -882,6 +884,9 @@ 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_->GetSiteInstance(), instance);
@@ -889,17 +894,22 @@ int RenderFrameHostManager::CreateRenderFrame(
// 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();
- 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.
@@ -912,21 +922,20 @@ int RenderFrameHostManager::CreateRenderFrame(
}
} 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 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 {
+ 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();
+
+ // 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.
@@ -934,13 +943,14 @@ int RenderFrameHostManager::CreateRenderFrame(
} 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_.reset(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,
@@ -1017,7 +1027,8 @@ void RenderFrameHostManager::CommitPending() {
// Swap in the pending frame and make it active. Also ensure the FrameTree
// stays in sync.
- RenderFrameHostImpl* old_render_frame_host = render_frame_host_.release();
+ 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();
@@ -1046,7 +1057,7 @@ void RenderFrameHostManager::CommitPending() {
&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);
@@ -1074,47 +1085,45 @@ void RenderFrameHostManager::CommitPending() {
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_->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
@@ -1122,23 +1131,23 @@ void RenderFrameHostManager::CommitPending() {
// swapped out list to simplify the deletion.
if (!static_cast<SiteInstanceImpl*>(
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(
@@ -1153,7 +1162,7 @@ void RenderFrameHostManager::ShutdownRenderFrameHostsInSiteInstance(
// |rvh| to Shutdown.
FrameTree* tree = rvh->GetDelegate()->GetFrameTree();
tree->ForEach(base::Bind(
- &RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance,
+ &RenderFrameHostManager::ClearProxiesInSiteInstance,
site_instance_id));
}
}
@@ -1321,8 +1330,8 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateRendererStateForNavigate(
}
void RenderFrameHostManager::CancelPending() {
- RenderFrameHostImpl* pending_render_frame_host =
- pending_render_frame_host_.release();
+ scoped_ptr<RenderFrameHostImpl> pending_render_frame_host =
+ pending_render_frame_host_.Pass();
RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
pending_render_frame_host->render_view_host(),
@@ -1331,18 +1340,21 @@ void RenderFrameHostManager::CancelPending() {
// 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();
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();
@@ -1369,11 +1381,11 @@ void RenderFrameHostManager::RenderViewDeleted(RenderViewHost* rvh) {
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();
+ for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
+ iter != proxy_hosts_.end();
++iter) {
if (iter->second->render_view_host() == rvh) {
- swapped_out_hosts_.erase(iter);
+ proxy_hosts_.erase(iter);
break;
}
}
@@ -1381,11 +1393,11 @@ void RenderFrameHostManager::RenderViewDeleted(RenderViewHost* rvh) {
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(
@@ -1393,28 +1405,27 @@ bool RenderFrameHostManager::IsOnSwappedOutList(
if (!rfh->GetSiteInstance())
return false;
- RenderFrameHostMap::const_iterator iter = swapped_out_hosts_.find(
+ RenderFrameProxyHostMap::const_iterator iter = proxy_hosts_.find(
rfh->GetSiteInstance()->GetId());
- if (iter == swapped_out_hosts_.end())
+ 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;
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index b06e2e3..c2ed883 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -30,6 +30,7 @@ class NavigationEntryImpl;
class RenderFrameHostDelegate;
class RenderFrameHostImpl;
class RenderFrameHostManagerTest;
+class RenderFrameProxyHost;
class RenderViewHost;
class RenderViewHostImpl;
class RenderWidgetHostDelegate;
@@ -268,9 +269,10 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
bool IsOnSwappedOutList(RenderFrameHostImpl* rfh) const;
// Returns the swapped out RenderViewHost or RenderFrameHost for the given
- // SiteInstance, if any.
+ // SiteInstance, if any. This method is *deprecated* and
+ // GetRenderFrameProxyHost should be used.
RenderViewHostImpl* GetSwappedOutRenderViewHost(SiteInstance* instance) const;
- RenderFrameHostImpl* GetSwappedOutRenderFrameHost(
+ RenderFrameProxyHost* GetRenderFrameProxyHost(
SiteInstance* instance) const;
// Runs the unload handler in the current page, when we know that a pending
@@ -331,10 +333,10 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
bool should_replace_current_entry;
};
- // Used with FrameTree::ForEach to erase inactive RenderFrameHosts from a
+ // Used with FrameTree::ForEach to erase RenderFrameProxyHosts from a
// FrameTreeNode's RenderFrameHostManager.
- static bool ClearSwappedOutRFHsInSiteInstance(int32 site_instance_id,
- FrameTreeNode* node);
+ static bool ClearProxiesInSiteInstance(int32 site_instance_id,
+ FrameTreeNode* node);
// Returns whether this tab should transition to a new renderer for
// cross-site URLs. Enabled unless we see the --process-per-tab command line
@@ -367,11 +369,11 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
bool force_browsing_instance_swap);
// Creates a RenderFrameHost and corresponding RenderViewHost if necessary.
- RenderFrameHostImpl* CreateRenderFrameHost(SiteInstance* instance,
- int view_routing_id,
- int frame_routing_id,
- bool swapped_out,
- bool hidden);
+ scoped_ptr<RenderFrameHostImpl> CreateRenderFrameHost(SiteInstance* instance,
+ int view_routing_id,
+ int frame_routing_id,
+ bool swapped_out,
+ bool hidden);
// Sets up the necessary state for a new RenderViewHost with the given opener,
// if necessary. Returns early if the RenderViewHost has already been
@@ -447,10 +449,9 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
scoped_ptr<WebUIImpl> pending_web_ui_;
base::WeakPtr<WebUIImpl> pending_and_current_web_ui_;
- // A map of site instance ID to swapped out RenderFrameHosts. This may
- // include pending_render_frame_host_ for navigations to existing entries.
- typedef base::hash_map<int32, RenderFrameHostImpl*> RenderFrameHostMap;
- RenderFrameHostMap swapped_out_hosts_;
+ // A map of site instance ID to RenderFrameProxyHosts.
+ typedef base::hash_map<int32, RenderFrameProxyHost*> RenderFrameProxyHostMap;
+ RenderFrameProxyHostMap proxy_hosts_;
// A map of RenderFrameHosts pending shutdown.
typedef base::hash_map<int32, linked_ptr<RenderFrameHostImpl> >
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index d43c63f..72e8b3a 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -125,6 +125,37 @@ class RenderViewHostDeletedObserver : public WebContentsObserver {
};
+// This observer keeps track of the last deleted RenderViewHost to avoid
+// accessing it and causing use-after-free condition.
+class RenderFrameHostDeletedObserver : public WebContentsObserver {
+ public:
+ RenderFrameHostDeletedObserver(RenderFrameHost* rfh)
+ : WebContentsObserver(WebContents::FromRenderFrameHost(rfh)),
+ process_id_(rfh->GetProcess()->GetID()),
+ routing_id_(rfh->GetRoutingID()),
+ deleted_(false) {
+ }
+
+ virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE {
+ if (render_frame_host->GetProcess()->GetID() == process_id_ &&
+ render_frame_host->GetRoutingID() == routing_id_) {
+ deleted_ = true;
+ }
+ }
+
+ bool deleted() {
+ return deleted_;
+ }
+
+ private:
+ int process_id_;
+ int routing_id_;
+ bool deleted_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver);
+};
+
+
// This observer is used to check whether IPC messages are being filtered for
// swapped out RenderFrameHost objects. It observes the plugin crash and favicon
// update events, which the FilterMessagesWhileSwappedOut test simulates being
@@ -1765,4 +1796,54 @@ TEST_F(RenderFrameHostManagerTest,
EXPECT_TRUE(rvh1->IsSwappedOut());
}
+// Test that a RenderFrameHost is properly deleted or swapped out when a
+// cross-site navigation is cancelled.
+TEST_F(RenderFrameHostManagerTest,
+ CancelPendingProperlyDeletesOrSwaps) {
+ const GURL kUrl1("http://www.google.com/");
+ const GURL kUrl2("http://www.chromium.org/");
+ RenderFrameHostImpl* pending_rfh = NULL;
+ base::TimeTicks now = base::TimeTicks::Now();
+
+ // Navigate to the first page.
+ contents()->NavigateAndCommit(kUrl1);
+ TestRenderViewHost* rvh1 = test_rvh();
+ EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+
+ // Navigate to a new site, starting a cross-site navigation.
+ controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ {
+ pending_rfh = contents()->GetFrameTree()->root()->render_manager()
+ ->pending_frame_host();
+ RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh);
+
+ // Cancel the navigation by simulating a declined beforeunload dialog.
+ main_test_rfh()->OnMessageReceived(
+ FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
+ EXPECT_FALSE(contents()->cross_navigation_pending());
+
+ // Since the pending RFH is the only one for the new SiteInstance, it should
+ // be deleted.
+ EXPECT_TRUE(rvh_deleted_observer.deleted());
+ }
+
+ // Start another cross-site navigation.
+ controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ {
+ pending_rfh = contents()->GetFrameTree()->root()->render_manager()
+ ->pending_frame_host();
+ RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh);
+
+ // Increment the number of active views in the new SiteInstance, which will
+ // cause the pending RFH to be swapped out instead of deleted.
+ static_cast<SiteInstanceImpl*>(
+ pending_rfh->GetSiteInstance())->increment_active_view_count();
+
+ main_test_rfh()->OnMessageReceived(
+ FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
+ EXPECT_FALSE(contents()->cross_navigation_pending());
+ EXPECT_FALSE(rvh_deleted_observer.deleted());
+ }
+}
+
} // namespace content
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
new file mode 100644
index 0000000..e965fda
--- /dev/null
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/frame_host/render_frame_proxy_host.h"
+
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/site_instance_impl.h"
+
+namespace content {
+
+RenderFrameProxyHost::RenderFrameProxyHost(
+ scoped_ptr<RenderFrameHostImpl> render_frame_host)
+ : site_instance_(render_frame_host->GetSiteInstance()),
+ render_frame_host_(render_frame_host.Pass()) {}
+
+RenderFrameProxyHost::~RenderFrameProxyHost() {}
+
+} // namespace content
diff --git a/content/browser/frame_host/render_frame_proxy_host.h b/content/browser/frame_host/render_frame_proxy_host.h
new file mode 100644
index 0000000..514f0b2
--- /dev/null
+++ b/content/browser/frame_host/render_frame_proxy_host.h
@@ -0,0 +1,88 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_PROXY_HOST_H_
+#define CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_PROXY_HOST_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/site_instance_impl.h"
+
+class RenderProcessHost;
+class RenderFrameHostImpl;
+class RenderViewHostImpl;
+
+namespace content {
+
+// When a page's frames are rendered by multiple processes, each renderer has a
+// full copy of the frame tree. It has full RenderFrames for the frames it is
+// responsible for rendering and placeholder objects (i.e., RenderFrameProxies)
+// for frames rendered by other processes.
+//
+// This class is the browser-side host object for the placeholder. Each node in
+// the frame tree has a RenderFrameHost for the active SiteInstance and a set
+// of RenderFrameProxyHost objects - one for all other SiteInstances with
+// references to this frame. The proxies allow us to keep existing window
+// references valid over cross-process navigations and route cross-site
+// asynchronous JavaScript calls, such as postMessage.
+//
+// For now, RenderFrameProxyHost is created when a RenderFrameHost is swapped
+// out and acts just as a wrapper. If a RenderFrameHost can be deleted, no
+// proxy object is created. It is destroyed when the RenderFrameHost is swapped
+// back in or is no longer referenced and is therefore deleted.
+//
+// Long term, RenderFrameProxyHost will be created whenever a cross-site
+// navigation occurs and a reference to the frame navigating needs to be kept
+// alive. A RenderFrameProxyHost and a RenderFrameHost for the same SiteInstance
+// can exist at the same time, but only one will be "active" at a time.
+// There are two cases where the two objects will coexist:
+// * When navigating cross-process and there is already a RenderFrameProxyHost
+// for the new SiteInstance. A pending RenderFrameHost is created, but it is
+// not used until it commits. At that point, RenderFrameHostManager transitions
+// the pending RenderFrameHost to the active one and deletes the proxy.
+// * When navigating cross-process and the existing document has an unload
+// event handler. When the new navigation commits, RenderFrameHostManager
+// creates a RenderFrameProxyHost for the old SiteInstance and uses it going
+// forward. It also instructs the RenderFrameHost to run the unload event
+// handler and is kept alive for the duration. Once the event handling is
+// complete, the RenderFrameHost is deleted.
+class RenderFrameProxyHost {
+ public:
+ explicit RenderFrameProxyHost(
+ scoped_ptr<RenderFrameHostImpl> render_frame_host);
+ ~RenderFrameProxyHost();
+
+ RenderProcessHost* GetProcess() {
+ return render_frame_host_->GetProcess();
+ }
+
+ SiteInstance* GetSiteInstance() {
+ return site_instance_.get();
+ }
+
+ // TODO(nasko): The following methods should be removed when swapping out
+ // of RenderFrameHosts is no longer used.
+ RenderFrameHostImpl* render_frame_host() {
+ return render_frame_host_.get();
+ }
+ RenderViewHostImpl* render_view_host() {
+ return render_frame_host_->render_view_host();
+ }
+ scoped_ptr<RenderFrameHostImpl> PassFrameHost() {
+ return render_frame_host_.Pass();
+ }
+
+ private:
+ scoped_refptr<SiteInstance> site_instance_;
+
+ // TODO(nasko): For now, hide the RenderFrameHost inside the proxy, but remove
+ // it once we have all the code support for proper proxy objects.
+ scoped_ptr<RenderFrameHostImpl> render_frame_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderFrameProxyHost);
+};
+
+} // namespace
+
+#endif // CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_PROXY_HOST_H_
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index c1bfe45..c0ea977d 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -566,6 +566,8 @@
'browser/frame_host/render_frame_host_manager.h',
'browser/frame_host/render_frame_message_filter.cc',
'browser/frame_host/render_frame_message_filter.h',
+ 'browser/frame_host/render_frame_proxy_host.cc',
+ 'browser/frame_host/render_frame_proxy_host.h',
'browser/frame_host/render_widget_host_view_child_frame.cc',
'browser/frame_host/render_widget_host_view_child_frame.h',
'browser/frame_host/render_widget_host_view_guest.cc',