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

Side by Side Diff: content/browser/frame_host/render_frame_host_manager.cc

Issue 88503002: Have the unload event execute in background on cross-site navigations (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added unit tests Created 6 years, 11 months 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/frame_host/render_frame_host_manager.h" 5 #include "content/browser/frame_host/render_frame_host_manager.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 RenderWidgetHostDelegate* render_widget_delegate, 65 RenderWidgetHostDelegate* render_widget_delegate,
66 Delegate* delegate) 66 Delegate* delegate)
67 : frame_tree_node_(frame_tree_node), 67 : frame_tree_node_(frame_tree_node),
68 delegate_(delegate), 68 delegate_(delegate),
69 cross_navigation_pending_(false), 69 cross_navigation_pending_(false),
70 render_frame_delegate_(render_frame_delegate), 70 render_frame_delegate_(render_frame_delegate),
71 render_view_delegate_(render_view_delegate), 71 render_view_delegate_(render_view_delegate),
72 render_widget_delegate_(render_widget_delegate), 72 render_widget_delegate_(render_widget_delegate),
73 render_frame_host_(NULL), 73 render_frame_host_(NULL),
74 pending_render_frame_host_(NULL), 74 pending_render_frame_host_(NULL),
75 interstitial_page_(NULL) { 75 interstitial_page_(NULL),
76 weak_factory_(this) {
76 } 77 }
77 78
78 RenderFrameHostManager::~RenderFrameHostManager() { 79 RenderFrameHostManager::~RenderFrameHostManager() {
79 if (pending_render_frame_host_) 80 if (pending_render_frame_host_)
80 CancelPending(); 81 CancelPending();
81 82
82 // We should always have a current RenderFrameHost except in some tests. 83 // We should always have a current RenderFrameHost except in some tests.
83 // TODO(creis): Now that we aren't using Shutdown, make render_frame_host_ and 84 // TODO(creis): Now that we aren't using Shutdown, make render_frame_host_ and
84 // RenderFrameHostMap use scoped_ptrs. 85 // RenderFrameHostMap use scoped_ptrs.
85 RenderFrameHostImpl* render_frame_host = render_frame_host_; 86 RenderFrameHostImpl* render_frame_host = render_frame_host_;
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 if (!cross_navigation_pending_) 226 if (!cross_navigation_pending_)
226 return true; 227 return true;
227 228
228 // We should always have a pending RFH when there's a cross-process navigation 229 // We should always have a pending RFH when there's a cross-process navigation
229 // in progress. Sanity check this for http://crbug.com/276333. 230 // in progress. Sanity check this for http://crbug.com/276333.
230 CHECK(pending_render_frame_host_); 231 CHECK(pending_render_frame_host_);
231 232
232 // If the tab becomes unresponsive during {before}unload while doing a 233 // If the tab becomes unresponsive during {before}unload while doing a
233 // cross-site navigation, proceed with the navigation. (This assumes that 234 // cross-site navigation, proceed with the navigation. (This assumes that
234 // the pending RenderFrameHost is still responsive.) 235 // the pending RenderFrameHost is still responsive.)
235 if (render_frame_host_->render_view_host()->is_waiting_for_unload_ack()) { 236 if (render_frame_host_->render_view_host()->IsWaitingForUnloadACK()) {
236 // The request has been started and paused while we're waiting for the 237 // The request has been started and paused while we're waiting for the
237 // unload handler to finish. We'll pretend that it did. The pending 238 // unload handler to finish. We'll pretend that it did. The pending
238 // renderer will then be swapped in as part of the usual DidNavigate logic. 239 // renderer will then be swapped in as part of the usual DidNavigate logic.
239 // (If the unload handler later finishes, this call will be ignored because 240 // (If the unload handler later finishes, this call will be ignored because
240 // the pending_nav_params_ state will already be cleaned up.) 241 // the pending_nav_params_ state will already be cleaned up.)
241 current_host()->OnSwappedOut(true); 242 current_host()->SwapOut();
nasko 2014/01/23 23:34:58 Calling SwapOut() will cause us to run the unload
clamy 2014/01/24 17:01:54 Done.
243 current_host()->OnSwappedOut(false);
242 } else if (render_frame_host_->render_view_host()-> 244 } else if (render_frame_host_->render_view_host()->
243 is_waiting_for_beforeunload_ack()) { 245 is_waiting_for_beforeunload_ack()) {
244 // Haven't gotten around to starting the request, because we're still 246 // Haven't gotten around to starting the request, because we're still
245 // waiting for the beforeunload handler to finish. We'll pretend that it 247 // waiting for the beforeunload handler to finish. We'll pretend that it
246 // did finish, to let the navigation proceed. Note that there's a danger 248 // did finish, to let the navigation proceed. Note that there's a danger
247 // that the beforeunload handler will later finish and possibly return 249 // that the beforeunload handler will later finish and possibly return
248 // false (meaning the navigation should not proceed), but we'll ignore it 250 // false (meaning the navigation should not proceed), but we'll ignore it
249 // in this case because it took too long. 251 // in this case because it took too long.
250 if (pending_render_frame_host_->render_view_host()-> 252 if (pending_render_frame_host_->render_view_host()->
251 are_navigations_suspended()) { 253 are_navigations_suspended()) {
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 // ResourceDispatcherHost has told us to run the onunload handler, which 530 // ResourceDispatcherHost has told us to run the onunload handler, which
529 // means it is not a download or unsafe page, and we are going to perform the 531 // means it is not a download or unsafe page, and we are going to perform the
530 // navigation. Thus, we no longer need to remember that the RenderFrameHost 532 // navigation. Thus, we no longer need to remember that the RenderFrameHost
531 // is part of a pending cross-site request. 533 // is part of a pending cross-site request.
532 if (pending_render_frame_host_) { 534 if (pending_render_frame_host_) {
533 pending_render_frame_host_->render_view_host()-> 535 pending_render_frame_host_->render_view_host()->
534 SetHasPendingCrossSiteRequest(false); 536 SetHasPendingCrossSiteRequest(false);
535 } 537 }
536 } 538 }
537 539
540 void RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance(
541 int32 site_instance_id,
542 RenderFrameHostImpl* rfh) {
543 base::hash_map<int32, linked_ptr<RenderFrameHostImpl> >::iterator iter =
544 pending_delete_hosts_.find(site_instance_id);
545 if (iter != pending_delete_hosts_.end() && iter->second.get() == rfh)
546 pending_delete_hosts_.erase(site_instance_id);
547 }
548
538 void RenderFrameHostManager::Observe( 549 void RenderFrameHostManager::Observe(
539 int type, 550 int type,
540 const NotificationSource& source, 551 const NotificationSource& source,
541 const NotificationDetails& details) { 552 const NotificationDetails& details) {
542 switch (type) { 553 switch (type) {
543 case NOTIFICATION_RENDERER_PROCESS_CLOSED: 554 case NOTIFICATION_RENDERER_PROCESS_CLOSED:
544 case NOTIFICATION_RENDERER_PROCESS_CLOSING: 555 case NOTIFICATION_RENDERER_PROCESS_CLOSING:
545 RendererProcessClosing( 556 RendererProcessClosing(
546 Source<RenderProcessHost>(source).ptr()); 557 Source<RenderProcessHost>(source).ptr());
547 break; 558 break;
548 559
549 default: 560 default:
550 NOTREACHED(); 561 NOTREACHED();
551 } 562 }
552 } 563 }
553 564
554 bool RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance( 565 bool RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance(
555 int32 site_instance_id, 566 int32 site_instance_id,
556 FrameTreeNode* node) { 567 FrameTreeNode* node) {
557 RenderFrameHostMap::iterator iter = 568 RenderFrameHostMap::iterator iter =
558 node->render_manager()->swapped_out_hosts_.find(site_instance_id); 569 node->render_manager()->swapped_out_hosts_.find(site_instance_id);
559 if (iter != node->render_manager()->swapped_out_hosts_.end()) 570 if (iter != node->render_manager()->swapped_out_hosts_.end()) {
560 delete iter->second; 571 RenderFrameHostImpl* swapped_out_rfh = iter->second;
572 // If the RVH is pending swap out, it needs to switch state to
573 // pending shutdown. Otherwise it is deleted.
574 if (swapped_out_rfh->render_view_host()->rvh_state() ==
575 RenderViewHostImpl::RVH_STATE_PENDING_SWAP_OUT) {
576 swapped_out_rfh->SetPendingShutdown(base::Bind(
577 &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
578 node->render_manager()->weak_factory_.GetWeakPtr(),
579 site_instance_id,
580 swapped_out_rfh));
581 RFHPendingDeleteMap::iterator pending_delete_iter =
582 node->render_manager()->pending_delete_hosts_.find(site_instance_id);
583 if (pending_delete_iter ==
584 node->render_manager()->pending_delete_hosts_.end() ||
585 pending_delete_iter->second.get() != iter->second) {
nasko 2014/01/23 23:34:58 What happens if there is already an entry for this
clamy 2014/01/24 17:01:54 Since it is stored in a linked_ptr, the only ref o
586 node->render_manager()->pending_delete_hosts_[site_instance_id] =
587 linked_ptr<RenderFrameHostImpl>(swapped_out_rfh);
588 }
589 } else {
590 delete swapped_out_rfh;
591 }
592 node->render_manager()->swapped_out_hosts_.erase(site_instance_id);
593 }
561 594
562 return true; 595 return true;
563 } 596 }
564 597
565 bool RenderFrameHostManager::ShouldTransitionCrossSite() { 598 bool RenderFrameHostManager::ShouldTransitionCrossSite() {
566 // False in the single-process mode, as it makes RVHs to accumulate 599 // False in the single-process mode, as it makes RVHs to accumulate
567 // in swapped_out_hosts_. 600 // in swapped_out_hosts_.
568 // True if we are using process-per-site-instance (default) or 601 // True if we are using process-per-site-instance (default) or
569 // process-per-site (kProcessPerSite). 602 // process-per-site (kProcessPerSite).
570 return 603 return
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
904 // If the pending navigation is to a WebUI and the RenderView is not in a 937 // If the pending navigation is to a WebUI and the RenderView is not in a
905 // guest process, tell the RenderViewHost about any bindings it will need 938 // guest process, tell the RenderViewHost about any bindings it will need
906 // enabled. 939 // enabled.
907 if (pending_web_ui() && !render_view_host->GetProcess()->IsGuest()) { 940 if (pending_web_ui() && !render_view_host->GetProcess()->IsGuest()) {
908 render_view_host->AllowBindings(pending_web_ui()->GetBindings()); 941 render_view_host->AllowBindings(pending_web_ui()->GetBindings());
909 } else { 942 } else {
910 // Ensure that we don't create an unprivileged RenderView in a WebUI-enabled 943 // Ensure that we don't create an unprivileged RenderView in a WebUI-enabled
911 // process unless it's swapped out. 944 // process unless it's swapped out.
912 RenderViewHostImpl* rvh_impl = 945 RenderViewHostImpl* rvh_impl =
913 static_cast<RenderViewHostImpl*>(render_view_host); 946 static_cast<RenderViewHostImpl*>(render_view_host);
914 if (!rvh_impl->is_swapped_out()) { 947 if (rvh_impl->rvh_state() != RenderViewHostImpl::RVH_STATE_SWAPPED_OUT) {
915 CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( 948 CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
916 render_view_host->GetProcess()->GetID())); 949 render_view_host->GetProcess()->GetID()));
917 } 950 }
918 } 951 }
919 952
920 return delegate_->CreateRenderViewForRenderManager(render_view_host, 953 return delegate_->CreateRenderViewForRenderManager(render_view_host,
921 opener_route_id); 954 opener_route_id);
922 } 955 }
923 956
924 void RenderFrameHostManager::CommitPending() { 957 void RenderFrameHostManager::CommitPending() {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
979 // to make sure the sad tab shows up, etc. 1012 // to make sure the sad tab shows up, etc.
980 if (!render_frame_host_->render_view_host()->GetView()) { 1013 if (!render_frame_host_->render_view_host()->GetView()) {
981 delegate_->RenderProcessGoneFromRenderManager( 1014 delegate_->RenderProcessGoneFromRenderManager(
982 render_frame_host_->render_view_host()); 1015 render_frame_host_->render_view_host());
983 } else if (!delegate_->IsHidden() && is_main_frame) { 1016 } else if (!delegate_->IsHidden() && is_main_frame) {
984 render_frame_host_->render_view_host()->GetView()->Show(); 1017 render_frame_host_->render_view_host()->GetView()->Show();
985 } 1018 }
986 1019
987 // If the old view is live and top-level, hide it now that the new one is 1020 // If the old view is live and top-level, hide it now that the new one is
988 // visible. 1021 // visible.
1022 int32 old_site_instance_id =
1023 old_render_frame_host->render_view_host()->GetSiteInstance()->GetId();
989 if (old_render_frame_host->render_view_host()->GetView()) { 1024 if (old_render_frame_host->render_view_host()->GetView()) {
990 if (is_main_frame) { 1025 if (is_main_frame) {
991 old_render_frame_host->render_view_host()->GetView()->Hide(); 1026 old_render_frame_host->render_view_host()->GetView()->Hide();
992 old_render_frame_host->render_view_host()->WasSwappedOut(); 1027 old_render_frame_host->render_view_host()->WasSwappedOut(base::Bind(
1028 &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
1029 weak_factory_.GetWeakPtr(),
1030 old_site_instance_id,
1031 old_render_frame_host));
993 } else { 1032 } else {
994 // TODO(creis): We'll need to set this back to false if we navigate back. 1033 // TODO(creis): We'll need to set this back to false if we navigate back.
995 old_render_frame_host->set_swapped_out(true); 1034 old_render_frame_host->set_swapped_out(true);
996 } 1035 }
997 } 1036 }
998 1037
999 // Make sure the size is up to date. (Fix for bug 1079768.) 1038 // Make sure the size is up to date. (Fix for bug 1079768.)
1000 delegate_->UpdateRenderViewSizeForRenderManager(); 1039 delegate_->UpdateRenderViewSizeForRenderManager();
1001 1040
1002 if (will_focus_location_bar) { 1041 if (will_focus_location_bar) {
(...skipping 13 matching lines...) Expand all
1016 old_render_frame_host->render_view_host(), 1055 old_render_frame_host->render_view_host(),
1017 render_frame_host_->render_view_host()); 1056 render_frame_host_->render_view_host());
1018 } 1057 }
1019 1058
1020 // If the pending frame was on the swapped out list, we can remove it. 1059 // If the pending frame was on the swapped out list, we can remove it.
1021 swapped_out_hosts_.erase(render_frame_host_->render_view_host()-> 1060 swapped_out_hosts_.erase(render_frame_host_->render_view_host()->
1022 GetSiteInstance()->GetId()); 1061 GetSiteInstance()->GetId());
1023 1062
1024 if (old_render_frame_host->render_view_host()->IsRenderViewLive()) { 1063 if (old_render_frame_host->render_view_host()->IsRenderViewLive()) {
1025 // If the old RFH is live, we are swapping it out and should keep track of 1064 // If the old RFH is live, we are swapping it out and should keep track of
1026 // it in case we navigate back to it. 1065 // it in case we navigate back to it, or it is waiting for the unload event
1066 // to execute in the background.
1027 // TODO(creis): Swap out the subframe in --site-per-process. 1067 // TODO(creis): Swap out the subframe in --site-per-process.
1028 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) 1068 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess))
1029 DCHECK(old_render_frame_host->is_swapped_out() || 1069 DCHECK(old_render_frame_host->is_swapped_out() ||
1030 old_render_frame_host->render_view_host()->is_swapped_out()); 1070 !RenderViewHostImpl::IsRVHStateActive(
1031 1071 old_render_frame_host->render_view_host()->rvh_state()));
1032 // Temp fix for http://crbug.com/90867 until we do a better cleanup to make 1072 // Temp fix for http://crbug.com/90867 until we do a better cleanup to make
1033 // sure we don't get different rvh instances for the same site instance 1073 // sure we don't get different rvh instances for the same site instance
1034 // in the same rvhmgr. 1074 // in the same rvhmgr.
1035 // TODO(creis): Clean this up. 1075 // TODO(creis): Clean this up.
1036 int32 old_site_instance_id =
1037 old_render_frame_host->render_view_host()->GetSiteInstance()->GetId();
1038 RenderFrameHostMap::iterator iter = 1076 RenderFrameHostMap::iterator iter =
1039 swapped_out_hosts_.find(old_site_instance_id); 1077 swapped_out_hosts_.find(old_site_instance_id);
1040 if (iter != swapped_out_hosts_.end() && 1078 if (iter != swapped_out_hosts_.end() &&
1041 iter->second != old_render_frame_host) { 1079 iter->second != old_render_frame_host) {
1042 // Delete the RFH that will be replaced in the map to avoid a leak. 1080 // Delete the RFH that will be replaced in the map to avoid a leak.
1043 delete iter->second; 1081 delete iter->second;
1044 } 1082 }
1045 swapped_out_hosts_[old_site_instance_id] = old_render_frame_host; 1083 // If the RenderViewHost backing the RenderFrameHost is pending shutdown,
nasko 2014/01/23 23:34:58 nit: You are mixing terminology - pending shutdown
clamy 2014/01/24 17:01:54 We call delete on the RenderFrameHost, which will
nasko 2014/01/27 19:09:51 I think it is best we keep it using "delete", sinc
1084 // the RenderFrameHost should be put in the map of RenderFrameHost pending
1085 // shutdown. Otherwise, it is stored in the map of swapped out
1086 // RenderFrameHosts.
1087 if (old_render_frame_host->render_view_host()->rvh_state() ==
1088 RenderViewHostImpl::RVH_STATE_PENDING_SHUTDOWN) {
1089 swapped_out_hosts_.erase(old_site_instance_id);
1090 RFHPendingDeleteMap::iterator pending_delete_iter =
1091 pending_delete_hosts_.find(old_site_instance_id);
1092 if (pending_delete_iter == pending_delete_hosts_.end() ||
1093 pending_delete_iter->second.get() != old_render_frame_host) {
1094 pending_delete_hosts_[old_site_instance_id] =
1095 linked_ptr<RenderFrameHostImpl>(old_render_frame_host);
1096 }
1097 } else {
1098 swapped_out_hosts_[old_site_instance_id] = old_render_frame_host;
1099 }
1046 1100
1047 // If there are no active views in this SiteInstance, it means that 1101 // If there are no active views in this SiteInstance, it means that
1048 // this RFH was the last active one in the SiteInstance. Now that we 1102 // this RFH was the last active one in the SiteInstance. Now that we
1049 // know that all RFHs are swapped out, we can delete all the RFHs and RVHs 1103 // know that all RFHs are swapped out, we can delete all the RFHs and RVHs
1050 // in this SiteInstance. We do this after ensuring the RFH is on the 1104 // in this SiteInstance. We do this after ensuring the RFH is on the
1051 // swapped out list to simplify the deletion. 1105 // swapped out list to simplify the deletion.
1052 if (!static_cast<SiteInstanceImpl*>( 1106 if (!static_cast<SiteInstanceImpl*>(
1053 old_render_frame_host->render_view_host()->GetSiteInstance())-> 1107 old_render_frame_host->render_view_host()->GetSiteInstance())->
1054 active_view_count()) { 1108 active_view_count()) {
1055 ShutdownRenderFrameHostsInSiteInstance(old_site_instance_id); 1109 ShutdownRenderFrameHostsInSiteInstance(old_site_instance_id);
(...skipping 22 matching lines...) Expand all
1078 continue; 1132 continue;
1079 RenderViewHostImpl* rvh = 1133 RenderViewHostImpl* rvh =
1080 static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget)); 1134 static_cast<RenderViewHostImpl*>(RenderViewHost::From(widget));
1081 if (site_instance_id == rvh->GetSiteInstance()->GetId()) { 1135 if (site_instance_id == rvh->GetSiteInstance()->GetId()) {
1082 // This deletes all RenderFrameHosts using the |rvh|, which then causes 1136 // This deletes all RenderFrameHosts using the |rvh|, which then causes
1083 // |rvh| to Shutdown. 1137 // |rvh| to Shutdown.
1084 FrameTree* tree = rvh->GetDelegate()->GetFrameTree(); 1138 FrameTree* tree = rvh->GetDelegate()->GetFrameTree();
1085 tree->ForEach(base::Bind( 1139 tree->ForEach(base::Bind(
1086 &RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance, 1140 &RenderFrameHostManager::ClearSwappedOutRFHsInSiteInstance,
1087 site_instance_id)); 1141 site_instance_id));
1088 // rvh is now deleted.
1089 } 1142 }
1090 } 1143 }
1091 } 1144 }
1092 1145
1093 RenderFrameHostImpl* RenderFrameHostManager::UpdateRendererStateForNavigate( 1146 RenderFrameHostImpl* RenderFrameHostManager::UpdateRendererStateForNavigate(
1094 const NavigationEntryImpl& entry) { 1147 const NavigationEntryImpl& entry) {
1095 // If we are currently navigating cross-process, we want to get back to normal 1148 // If we are currently navigating cross-process, we want to get back to normal
1096 // and then navigate as usual. 1149 // and then navigate as usual.
1097 if (cross_navigation_pending_) { 1150 if (cross_navigation_pending_) {
1098 if (pending_render_frame_host_) 1151 if (pending_render_frame_host_)
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
1347 SiteInstance* instance) const { 1400 SiteInstance* instance) const {
1348 RenderFrameHostMap::const_iterator iter = 1401 RenderFrameHostMap::const_iterator iter =
1349 swapped_out_hosts_.find(instance->GetId()); 1402 swapped_out_hosts_.find(instance->GetId());
1350 if (iter != swapped_out_hosts_.end()) 1403 if (iter != swapped_out_hosts_.end())
1351 return iter->second; 1404 return iter->second;
1352 1405
1353 return NULL; 1406 return NULL;
1354 } 1407 }
1355 1408
1356 } // namespace content 1409 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698