Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Unified Diff: content/browser/frame_host/render_frame_host_manager.cc

Issue 701953006: PlzNavigate: Speculatively spawns a renderer process for navigations. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address CR comments and fix possible RFH double swap out. Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/frame_host/render_frame_host_manager.cc
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 06ab825123e4b1fd294dd577e6aee18ab9ff94fe..990ba4334ff9d479f0409c0d2a708324ec94b99e 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -61,7 +61,8 @@ RenderFrameHostManager::RenderFrameHostManager(
render_view_delegate_(render_view_delegate),
render_widget_delegate_(render_widget_delegate),
interstitial_page_(NULL),
- weak_factory_(this) {
+ weak_factory_(this),
Charlie Reis 2014/12/04 21:46:28 weak_factory_ must be last.
carlosk 2014/12/09 07:55:41 Done.
+ should_reuse_web_ui_(false) {
DCHECK(frame_tree_node_);
}
@@ -69,6 +70,11 @@ RenderFrameHostManager::~RenderFrameHostManager() {
if (pending_render_frame_host_)
CancelPending();
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ CleanUpNavigation();
+ }
+
// We should always have a current RenderFrameHost except in some tests.
SetRenderFrameHost(scoped_ptr<RenderFrameHostImpl>());
@@ -288,6 +294,8 @@ void RenderFrameHostManager::OnBeforeUnloadACK(
bool proceed,
const base::TimeTicks& proceed_time) {
if (for_cross_site_transition) {
+ DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
// Ignore if we're not in a cross-site navigation.
if (!cross_navigation_pending_)
return;
@@ -419,6 +427,12 @@ void RenderFrameHostManager::ClearNavigationTransitionData() {
void RenderFrameHostManager::DidNavigateFrame(
RenderFrameHostImpl* render_frame_host) {
+ DCHECK(render_frame_host);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ return;
Charlie Reis 2014/12/04 21:46:28 I'm not sure this is correct. What happens if a D
clamy 2014/12/05 17:16:19 If we go along with committing the NavigationEntry
Charlie Reis 2014/12/05 19:06:23 I'm nervous about this as well: ignoring a commit
carlosk 2014/12/09 07:55:42 I'm having trouble following your lines of thought
clamy 2014/12/09 15:09:51 Indeed, it seems we are in agreement that the spec
carlosk 2014/12/16 01:53:47 Done.
+ }
+
if (!cross_navigation_pending_) {
DCHECK(!pending_render_frame_host_);
@@ -574,7 +588,10 @@ void RenderFrameHostManager::DiscardUnusedFrame(
RenderFrameProxyHost* proxy =
new RenderFrameProxyHost(site_instance, frame_tree_node_);
proxy_hosts_[site_instance->GetId()] = proxy;
- render_frame_host->SwapOut(proxy);
+
+ if (!render_frame_host->is_swapped_out())
+ render_frame_host->SwapOut(proxy);
+
if (frame_tree_node_->IsMainFrame())
proxy->TakeFrameHostOwnership(render_frame_host.Pass());
} else {
@@ -619,6 +636,88 @@ void RenderFrameHostManager::ResetProxyHosts() {
}
// PlzNavigate
+void RenderFrameHostManager::BeginNavigation(
Charlie Reis 2014/12/04 21:46:28 This code looks a lot like UpdateStateForNavigate,
carlosk 2014/12/09 07:55:42 Both methods do check if the current SiteInstance
+ const FrameHostMsg_BeginNavigation_Params& params,
+ const CommonNavigationParams& common_params) {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ // If there is an ongoing navigation, cancel it.
Charlie Reis 2014/12/04 21:46:28 cancel it -> cancel any state we have for it. (RF
clamy 2014/12/05 17:16:19 NavigatorImpl is normally responsible for cancelin
carlosk 2014/12/09 07:55:42 Updated the comment. This was more of a just-in-c
clamy 2014/12/09 15:09:52 The way the code is written, there would not have
carlosk 2014/12/16 01:53:47 It is already being called in NavigatorImpl::Cance
+ CleanUpNavigation();
+
+ SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
+ // TODO(carlosk): Replace the default values with the right ones.
Charlie Reis 2014/12/04 21:46:28 I see this is the same TODO as in GetFrameHostForN
clamy 2014/12/05 17:16:19 Note that it also concerns the SiteInstance pointe
carlosk 2014/12/09 07:55:42 Updated comment.
+ scoped_refptr<SiteInstanceImpl> new_instance =
+ static_cast<SiteInstanceImpl*>(GetSiteInstanceForNavigation(
+ common_params.url, nullptr, common_params.transition, false, false));
+
+ if (new_instance.get() != current_instance &&
+ (frame_tree_node_->IsMainFrame() ||
Charlie Reis 2014/12/04 21:46:28 These additional checks are non-obvious, so please
clamy 2014/12/05 17:16:19 In that case, we need to be able to distinguish he
Charlie Reis 2014/12/05 19:06:23 Yes, but this is an important TODO we'll need to r
carlosk 2014/12/09 07:55:42 I inverted the logic here to match the similar sni
clamy 2014/12/09 15:09:51 I think it is fine to have an if-block with just a
carlosk 2014/12/16 01:53:47 Done!
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))) {
+ // Navigating to a new SiteInstance -> speculatively create a new RFH.
+
+ // TODO(carlosk): enable bindings check below.
+ bool success = CreateSpeculativeRenderFrameHost(
+ common_params.url, current_instance, new_instance.get(),
+ NavigationEntryImpl::kInvalidBindings);
+ if (!success)
+ return;
+ DCHECK(new_instance->GetProcess()->HasConnection());
+ DCHECK(new_instance->GetProcess()->GetBrowserContext());
Charlie Reis 2014/12/04 21:46:28 This second check seems unnecessary. Is there a w
carlosk 2014/12/09 07:55:42 I was going to say this was a copy/paste from anot
+ } else {
Charlie Reis 2014/12/04 21:46:28 nit: Return here inside the previous block, so tha
carlosk 2014/12/09 07:55:42 Done.
+ // Navigating to the same SiteInstance -> make sure the current RFH is
+ // alive.
+ if (!render_frame_host_->render_view_host()->IsRenderViewLive()) {
+ // Recreate the opener chain.
+ int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
+ render_frame_host_->GetSiteInstance());
+ if (!InitRenderView(render_frame_host_->render_view_host(),
+ opener_route_id, MSG_ROUTING_NONE,
+ frame_tree_node_->IsMainFrame())) {
+ return;
+ }
+ }
+ DCHECK(current_instance->GetProcess()->HasConnection());
+ DCHECK(current_instance->GetProcess()->GetBrowserContext());
+ }
+}
+
+// PlzNavigate
+bool RenderFrameHostManager::CreateSpeculativeRenderFrameHost(
+ const GURL& url,
+ SiteInstance* old_instance,
+ SiteInstance* new_instance,
+ int bindings) {
+ CHECK(new_instance);
+ CHECK_NE(old_instance, new_instance);
+
+ const NavigationEntry* current_navigation_entry =
+ delegate_->GetLastCommittedNavigationEntryForRenderManager();
+ scoped_ptr<WebUIImpl> new_web_ui;
+ should_reuse_web_ui_ = ShouldReuseWebUI(current_navigation_entry, url);
+ if (!should_reuse_web_ui_)
+ new_web_ui = CreateWebUI(url, bindings);
+
+ int opener_route_id =
+ CreateOpenerRenderViewsIfNeeded(old_instance, new_instance);
+
+ int create_render_frame_flags = 0;
+ if (frame_tree_node_->IsMainFrame())
+ create_render_frame_flags |= CREATE_RF_FOR_MAIN_FRAME_NAVIGATION;
+ if (delegate_->IsHidden())
+ create_render_frame_flags |= CREATE_RF_HIDDEN;
+ scoped_ptr<RenderFrameHostImpl> new_render_frame_host =
+ CreateRenderFrame(new_instance, new_web_ui.get(), opener_route_id,
+ create_render_frame_flags, nullptr);
+ if (!new_render_frame_host) {
+ return false;
+ }
+ speculative_render_frame_host_.reset(new_render_frame_host.release());
+ speculative_web_ui_.reset(new_web_ui.release());
+ return true;
+}
+
+// PlzNavigate
RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation(
const GURL& url,
ui::PageTransition transition) {
@@ -650,6 +749,19 @@ RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation(
return render_frame_host;
}
+// PlzNavigate
+void RenderFrameHostManager::CleanUpNavigation() {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ if (speculative_render_frame_host_) {
+ speculative_render_frame_host_->GetProcess()->RemovePendingView();
+ DiscardUnusedFrame(speculative_render_frame_host_.Pass());
+ }
+ if (speculative_web_ui_)
+ speculative_web_ui_.reset();
+ should_reuse_web_ui_ = false;
+}
+
void RenderFrameHostManager::Observe(
int type,
const NotificationSource& source,
@@ -1110,8 +1222,8 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrame(
if (view_routing_id_ptr)
*view_routing_id_ptr = 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.
+ // We are creating a pending, speculative 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);
// Check if we've already created an RFH for this SiteInstance. If so, try
@@ -1294,23 +1406,32 @@ void RenderFrameHostManager::CommitPending() {
// this triggers won't be able to figure out what's going on.
bool will_focus_location_bar = delegate_->FocusLocationBarByDefault();
- // Next commit the Web UI, if any. Either replace |web_ui_| with
- // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or
- // leave |web_ui_| as is if reusing it.
- 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();
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
Charlie Reis 2014/12/04 21:46:28 Please cache this in a bool so we don't repeatedly
carlosk 2014/12/09 07:55:42 Ha! I had just undone that. :) Re-added the boolea
+ switches::kEnableBrowserSideNavigation)) {
+ DCHECK(!speculative_web_ui_);
+ // Next commit the Web UI, if any. Either replace |web_ui_| with
+ // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or
+ // leave |web_ui_| as is if reusing it.
+ 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();
+ }
} else {
- DCHECK_EQ(pending_and_current_web_ui_.get(), web_ui_.get());
- pending_and_current_web_ui_.reset();
+ if (!should_reuse_web_ui_)
+ web_ui_.reset(speculative_web_ui_.release());
Charlie Reis 2014/12/04 21:46:28 Let's add a DCHECK(!speculative_web_ui_) after thi
carlosk 2014/12/09 07:55:42 Done.
}
// It's possible for the pending_render_frame_host_ to be NULL when we aren't
// crossing process boundaries. If so, we just needed to handle the Web UI
// committing above and we're done.
- if (!pending_render_frame_host_) {
+ if (!pending_render_frame_host_ &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
Charlie Reis 2014/12/04 21:46:28 Can we make this !pending_render_frame_host_ && !s
carlosk 2014/12/09 07:55:42 Makes sense. Done.
if (will_focus_location_bar)
delegate_->SetFocusToLocationBar(false);
return;
@@ -1324,10 +1445,20 @@ void RenderFrameHostManager::CommitPending() {
bool is_main_frame = frame_tree_node_->IsMainFrame();
- // Swap in the pending frame and make it active. Also ensure the FrameTree
- // stays in sync.
- scoped_ptr<RenderFrameHostImpl> old_render_frame_host =
- SetRenderFrameHost(pending_render_frame_host_.Pass());
+ scoped_ptr<RenderFrameHostImpl> old_render_frame_host;
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ DCHECK(!speculative_render_frame_host_);
+ // Swap in the pending frame and make it active. Also ensure the FrameTree
+ // stays in sync.
+ old_render_frame_host =
+ SetRenderFrameHost(pending_render_frame_host_.Pass());
+ } else {
+ DCHECK(speculative_render_frame_host_);
+ old_render_frame_host =
+ SetRenderFrameHost(speculative_render_frame_host_.Pass());
+ }
+
if (is_main_frame)
render_frame_host_->render_view_host()->AttachToFrameTree();
@@ -1456,6 +1587,36 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation(
url, instance, transition, is_restore, is_view_source_mode);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
Charlie Reis 2014/12/04 21:46:28 This doesn't feel like it fits here. Most of Upda
carlosk 2014/12/09 07:55:42 Makes total sense and so I moved it. It might nee
+ switches::kEnableBrowserSideNavigation)) {
+ if (current_instance == new_instance.get() ||
+ (!frame_tree_node_->IsMainFrame() &&
Charlie Reis 2014/12/04 21:46:28 Same concern about the process model policy.
carlosk 2014/12/09 07:55:41 Done: TODO + reference in crbug.com/440266 .
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))) {
+ CleanUpNavigation();
+ } else {
+ // If the SiteInstance for the final URL doesn't match the one from the
+ // speculatively created RenderFrameHost, create a new one using the
+ // former.
+ if (!speculative_render_frame_host_ ||
+ speculative_render_frame_host_->GetSiteInstance() !=
+ new_instance.get()) {
+ CleanUpNavigation();
+ // TODO(carlosk): Should rename this method and the speculative members
Charlie Reis 2014/12/04 21:46:28 I'm not concerned about the name. We're creating
carlosk 2014/12/09 07:55:41 Great! Later on I realized that as soon as we begi
+ // because in this case they are not speculative. Suggestions are
+ // very welcome!
+ bool success = CreateSpeculativeRenderFrameHost(
+ url, current_instance, new_instance.get(), bindings);
+ if (!success)
+ return nullptr;
+ }
+ DCHECK(speculative_render_frame_host_);
+ CommitPending();
+ DCHECK(!speculative_render_frame_host_);
+ }
+ return render_frame_host_.get();
+ }
+
const NavigationEntry* current_entry =
delegate_->GetLastCommittedNavigationEntryForRenderManager();

Powered by Google App Engine
This is Rietveld 408576698