| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/web_contents/render_view_host_manager.h" | 5 #include "content/browser/web_contents/render_view_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 14 matching lines...) Expand all Loading... |
| 25 #include "content/public/browser/notification_service.h" | 25 #include "content/public/browser/notification_service.h" |
| 26 #include "content/public/browser/notification_types.h" | 26 #include "content/public/browser/notification_types.h" |
| 27 #include "content/public/browser/user_metrics.h" | 27 #include "content/public/browser/user_metrics.h" |
| 28 #include "content/public/browser/web_contents_view.h" | 28 #include "content/public/browser/web_contents_view.h" |
| 29 #include "content/public/browser/web_ui_controller.h" | 29 #include "content/public/browser/web_ui_controller.h" |
| 30 #include "content/public/common/content_switches.h" | 30 #include "content/public/common/content_switches.h" |
| 31 #include "content/public/common/url_constants.h" | 31 #include "content/public/common/url_constants.h" |
| 32 | 32 |
| 33 namespace content { | 33 namespace content { |
| 34 | 34 |
| 35 RenderViewHostManager::PendingNavigationParams::PendingNavigationParams() { |
| 36 } |
| 37 |
| 38 RenderViewHostManager::PendingNavigationParams::PendingNavigationParams( |
| 39 const GlobalRequestID& global_request_id) |
| 40 : global_request_id(global_request_id) { |
| 41 } |
| 42 |
| 35 RenderViewHostManager::RenderViewHostManager( | 43 RenderViewHostManager::RenderViewHostManager( |
| 36 RenderViewHostDelegate* render_view_delegate, | 44 RenderViewHostDelegate* render_view_delegate, |
| 37 RenderWidgetHostDelegate* render_widget_delegate, | 45 RenderWidgetHostDelegate* render_widget_delegate, |
| 38 Delegate* delegate) | 46 Delegate* delegate) |
| 39 : delegate_(delegate), | 47 : delegate_(delegate), |
| 40 cross_navigation_pending_(false), | 48 cross_navigation_pending_(false), |
| 41 render_view_delegate_(render_view_delegate), | 49 render_view_delegate_(render_view_delegate), |
| 42 render_widget_delegate_(render_widget_delegate), | 50 render_widget_delegate_(render_widget_delegate), |
| 43 render_view_host_(NULL), | 51 render_view_host_(NULL), |
| 44 pending_render_view_host_(NULL), | 52 pending_render_view_host_(NULL), |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 void RenderViewHostManager::SetIsLoading(bool is_loading) { | 189 void RenderViewHostManager::SetIsLoading(bool is_loading) { |
| 182 render_view_host_->SetIsLoading(is_loading); | 190 render_view_host_->SetIsLoading(is_loading); |
| 183 if (pending_render_view_host_) | 191 if (pending_render_view_host_) |
| 184 pending_render_view_host_->SetIsLoading(is_loading); | 192 pending_render_view_host_->SetIsLoading(is_loading); |
| 185 } | 193 } |
| 186 | 194 |
| 187 bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() { | 195 bool RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() { |
| 188 if (!cross_navigation_pending_) | 196 if (!cross_navigation_pending_) |
| 189 return true; | 197 return true; |
| 190 | 198 |
| 191 // If the tab becomes unresponsive during unload while doing a | 199 // If the tab becomes unresponsive during {before}unload while doing a |
| 192 // cross-site navigation, proceed with the navigation. (This assumes that | 200 // cross-site navigation, proceed with the navigation. (This assumes that |
| 193 // the pending RenderViewHost is still responsive.) | 201 // the pending RenderViewHost is still responsive.) |
| 194 int pending_request_id = pending_render_view_host_->GetPendingRequestId(); | 202 if (render_view_host_->is_waiting_for_unload_ack()) { |
| 195 if (pending_request_id == -1) { | 203 // The request has been started and paused while we're waiting for the |
| 204 // unload handler to finish. We'll pretend that it did. The pending |
| 205 // renderer will then be swapped in as part of the usual DidNavigate logic. |
| 206 // (If the unload handler later finishes, this call will be ignored because |
| 207 // the pending_nav_params_ state will already be cleaned up.) |
| 208 current_host()->OnSwappedOut(true); |
| 209 } else if (render_view_host_->is_waiting_for_beforeunload_ack()) { |
| 196 // Haven't gotten around to starting the request, because we're still | 210 // Haven't gotten around to starting the request, because we're still |
| 197 // waiting for the beforeunload handler to finish. We'll pretend that it | 211 // waiting for the beforeunload handler to finish. We'll pretend that it |
| 198 // did finish, to let the navigation proceed. Note that there's a danger | 212 // did finish, to let the navigation proceed. Note that there's a danger |
| 199 // that the beforeunload handler will later finish and possibly return | 213 // that the beforeunload handler will later finish and possibly return |
| 200 // false (meaning the navigation should not proceed), but we'll ignore it | 214 // false (meaning the navigation should not proceed), but we'll ignore it |
| 201 // in this case because it took too long. | 215 // in this case because it took too long. |
| 202 if (pending_render_view_host_->are_navigations_suspended()) | 216 if (pending_render_view_host_->are_navigations_suspended()) |
| 203 pending_render_view_host_->SetNavigationsSuspended( | 217 pending_render_view_host_->SetNavigationsSuspended( |
| 204 false, base::TimeTicks::Now()); | 218 false, base::TimeTicks::Now()); |
| 205 } else { | |
| 206 // The request has been started and paused while we're waiting for the | |
| 207 // unload handler to finish. We'll pretend that it did, by notifying the | |
| 208 // IO thread to let the response continue. The pending renderer will then | |
| 209 // be swapped in as part of the usual DidNavigate logic. (If the unload | |
| 210 // handler later finishes, this call will be ignored because the state in | |
| 211 // CrossSiteResourceHandler will already be cleaned up.) | |
| 212 ViewMsg_SwapOut_Params params; | |
| 213 params.closing_process_id = render_view_host_->GetProcess()->GetID(); | |
| 214 params.closing_route_id = render_view_host_->GetRoutingID(); | |
| 215 params.new_render_process_host_id = | |
| 216 pending_render_view_host_->GetProcess()->GetID(); | |
| 217 params.new_request_id = pending_request_id; | |
| 218 current_host()->GetProcess()->SimulateSwapOutACK(params); | |
| 219 } | 219 } |
| 220 return false; | 220 return false; |
| 221 } | 221 } |
| 222 | 222 |
| 223 void RenderViewHostManager::SwappedOut(RenderViewHost* render_view_host) { |
| 224 // Make sure this is from our current RVH, and that we have a pending |
| 225 // navigation from OnCrossSiteResponse. (There may be no pending navigation |
| 226 // for data URLs that don't make network requests, for example.) If not, |
| 227 // just return early and ignore. |
| 228 if (render_view_host != render_view_host_ || !pending_nav_params_.get()) { |
| 229 pending_nav_params_.reset(); |
| 230 return; |
| 231 } |
| 232 |
| 233 // Now that the unload handler has run, we need to resume the paused response. |
| 234 if (pending_render_view_host_) { |
| 235 RenderProcessHostImpl* pending_process = |
| 236 static_cast<RenderProcessHostImpl*>( |
| 237 pending_render_view_host_->GetProcess()); |
| 238 pending_process->ResumeDeferredNavigation( |
| 239 pending_nav_params_->global_request_id); |
| 240 } |
| 241 pending_nav_params_.reset(); |
| 242 } |
| 243 |
| 223 void RenderViewHostManager::DidNavigateMainFrame( | 244 void RenderViewHostManager::DidNavigateMainFrame( |
| 224 RenderViewHost* render_view_host) { | 245 RenderViewHost* render_view_host) { |
| 225 if (!cross_navigation_pending_) { | 246 if (!cross_navigation_pending_) { |
| 226 DCHECK(!pending_render_view_host_); | 247 DCHECK(!pending_render_view_host_); |
| 227 | 248 |
| 228 // We should only hear this from our current renderer. | 249 // We should only hear this from our current renderer. |
| 229 DCHECK(render_view_host == render_view_host_); | 250 DCHECK(render_view_host == render_view_host_); |
| 230 | 251 |
| 231 // Even when there is no pending RVH, there may be a pending Web UI. | 252 // Even when there is no pending RVH, there may be a pending Web UI. |
| 232 if (pending_web_ui()) | 253 if (pending_web_ui()) |
| 233 CommitPending(); | 254 CommitPending(); |
| 234 return; | 255 return; |
| 235 } | 256 } |
| 236 | 257 |
| 237 if (render_view_host == pending_render_view_host_) { | 258 if (render_view_host == pending_render_view_host_) { |
| 238 // The pending cross-site navigation completed, so show the renderer. | 259 // The pending cross-site navigation completed, so show the renderer. |
| 239 // If it committed without sending network requests (e.g., data URLs), | 260 // If it committed without sending network requests (e.g., data URLs), |
| 240 // then we still need to swap out the old RVH first and run its unload | 261 // then we still need to swap out the old RVH first and run its unload |
| 241 // handler. OK for that to happen in the background. | 262 // handler. OK for that to happen in the background. |
| 242 if (pending_render_view_host_->GetPendingRequestId() == -1) { | 263 if (pending_render_view_host_->HasPendingCrossSiteRequest()) |
| 243 OnCrossSiteResponse(pending_render_view_host_->GetProcess()->GetID(), | 264 SwapOutOldPage(); |
| 244 pending_render_view_host_->GetRoutingID()); | |
| 245 } | |
| 246 | 265 |
| 247 CommitPending(); | 266 CommitPending(); |
| 248 cross_navigation_pending_ = false; | 267 cross_navigation_pending_ = false; |
| 249 } else if (render_view_host == render_view_host_) { | 268 } else if (render_view_host == render_view_host_) { |
| 250 // A navigation in the original page has taken place. Cancel the pending | 269 // A navigation in the original page has taken place. Cancel the pending |
| 251 // one. | 270 // one. |
| 252 CancelPending(); | 271 CancelPending(); |
| 253 cross_navigation_pending_ = false; | 272 cross_navigation_pending_ = false; |
| 254 } else { | 273 } else { |
| 255 // No one else should be sending us DidNavigate in this state. | 274 // No one else should be sending us DidNavigate in this state. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time, | 352 delegate_->BeforeUnloadFiredFromRenderManager(proceed, proceed_time, |
| 334 &proceed_to_fire_unload); | 353 &proceed_to_fire_unload); |
| 335 | 354 |
| 336 if (proceed_to_fire_unload) { | 355 if (proceed_to_fire_unload) { |
| 337 // This is not a cross-site navigation, the tab is being closed. | 356 // This is not a cross-site navigation, the tab is being closed. |
| 338 render_view_host_->ClosePage(); | 357 render_view_host_->ClosePage(); |
| 339 } | 358 } |
| 340 } | 359 } |
| 341 } | 360 } |
| 342 | 361 |
| 343 void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id, | 362 void RenderViewHostManager::OnCrossSiteResponse( |
| 344 int new_request_id) { | 363 RenderViewHost* pending_render_view_host, |
| 364 const GlobalRequestID& global_request_id) { |
| 365 // This should be called when the pending RVH is ready to commit. |
| 366 DCHECK_EQ(pending_render_view_host_, pending_render_view_host); |
| 367 |
| 368 // Remember the request ID until the unload handler has run. |
| 369 pending_nav_params_.reset(new PendingNavigationParams(global_request_id)); |
| 370 |
| 371 // Run the unload handler of the current page. |
| 372 SwapOutOldPage(); |
| 373 } |
| 374 |
| 375 void RenderViewHostManager::SwapOutOldPage() { |
| 345 // Should only see this while we have a pending renderer. | 376 // Should only see this while we have a pending renderer. |
| 346 if (!cross_navigation_pending_) | 377 if (!cross_navigation_pending_) |
| 347 return; | 378 return; |
| 348 DCHECK(pending_render_view_host_); | 379 DCHECK(pending_render_view_host_); |
| 349 | 380 |
| 350 // Tell the old renderer it is being swapped out. This will fire the unload | 381 // Tell the old renderer it is being swapped out. This will fire the unload |
| 351 // handler (without firing the beforeunload handler a second time). When the | 382 // handler (without firing the beforeunload handler a second time). When the |
| 352 // unload handler finishes and the navigation completes, we will send a | 383 // unload handler finishes and the navigation completes, we will send a |
| 353 // message to the ResourceDispatcherHost with the given pending request IDs, | 384 // message to the ResourceDispatcherHost, allowing the pending RVH's response |
| 354 // allowing the pending RVH's response to resume. | 385 // to resume. |
| 355 render_view_host_->SwapOut(new_render_process_host_id, new_request_id); | 386 render_view_host_->SwapOut(); |
| 356 | 387 |
| 357 // ResourceDispatcherHost has told us to run the onunload handler, which | 388 // ResourceDispatcherHost has told us to run the onunload handler, which |
| 358 // means it is not a download or unsafe page, and we are going to perform the | 389 // means it is not a download or unsafe page, and we are going to perform the |
| 359 // navigation. Thus, we no longer need to remember that the RenderViewHost | 390 // navigation. Thus, we no longer need to remember that the RenderViewHost |
| 360 // is part of a pending cross-site request. | 391 // is part of a pending cross-site request. |
| 361 pending_render_view_host_->SetHasPendingCrossSiteRequest(false, | 392 pending_render_view_host_->SetHasPendingCrossSiteRequest(false); |
| 362 new_request_id); | |
| 363 } | 393 } |
| 364 | 394 |
| 365 void RenderViewHostManager::Observe( | 395 void RenderViewHostManager::Observe( |
| 366 int type, | 396 int type, |
| 367 const NotificationSource& source, | 397 const NotificationSource& source, |
| 368 const NotificationDetails& details) { | 398 const NotificationDetails& details) { |
| 369 switch (type) { | 399 switch (type) { |
| 370 case NOTIFICATION_RENDERER_PROCESS_CLOSING: | 400 case NOTIFICATION_RENDERER_PROCESS_CLOSING: |
| 371 RendererProcessClosing( | 401 RendererProcessClosing( |
| 372 Source<RenderProcessHost>(source).ptr()); | 402 Source<RenderProcessHost>(source).ptr()); |
| (...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 render_view_host_->Send( | 881 render_view_host_->Send( |
| 852 new ViewMsg_Stop(render_view_host_->GetRoutingID())); | 882 new ViewMsg_Stop(render_view_host_->GetRoutingID())); |
| 853 | 883 |
| 854 pending_render_view_host_->SetNavigationsSuspended(true, | 884 pending_render_view_host_->SetNavigationsSuspended(true, |
| 855 base::TimeTicks()); | 885 base::TimeTicks()); |
| 856 } | 886 } |
| 857 | 887 |
| 858 // Tell the CrossSiteRequestManager that this RVH has a pending cross-site | 888 // Tell the CrossSiteRequestManager that this RVH has a pending cross-site |
| 859 // request, so that ResourceDispatcherHost will know to tell us to run the | 889 // request, so that ResourceDispatcherHost will know to tell us to run the |
| 860 // old page's unload handler before it sends the response. | 890 // old page's unload handler before it sends the response. |
| 861 pending_render_view_host_->SetHasPendingCrossSiteRequest(true, -1); | 891 pending_render_view_host_->SetHasPendingCrossSiteRequest(true); |
| 862 | 892 |
| 863 // We now have a pending RVH. | 893 // We now have a pending RVH. |
| 864 DCHECK(!cross_navigation_pending_); | 894 DCHECK(!cross_navigation_pending_); |
| 865 cross_navigation_pending_ = true; | 895 cross_navigation_pending_ = true; |
| 866 | 896 |
| 867 // Unless we are transferring an existing request, we should now | 897 // Unless we are transferring an existing request, we should now |
| 868 // tell the old render view to run its beforeunload handler, since it | 898 // tell the old render view to run its beforeunload handler, since it |
| 869 // doesn't otherwise know that the cross-site request is happening. This | 899 // doesn't otherwise know that the cross-site request is happening. This |
| 870 // will trigger a call to ShouldClosePage with the reply. | 900 // will trigger a call to ShouldClosePage with the reply. |
| 871 if (!is_transfer) | 901 if (!is_transfer) |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 pending_render_view_host->GetProcess()->RemovePendingView(); | 943 pending_render_view_host->GetProcess()->RemovePendingView(); |
| 914 | 944 |
| 915 // The pending RVH may already be on the swapped out list if we started to | 945 // The pending RVH may already be on the swapped out list if we started to |
| 916 // swap it back in and then canceled. If so, make sure it gets swapped out | 946 // swap it back in and then canceled. If so, make sure it gets swapped out |
| 917 // again. If it's not on the swapped out list (e.g., aborting a pending | 947 // again. If it's not on the swapped out list (e.g., aborting a pending |
| 918 // load), then it's safe to shut down. | 948 // load), then it's safe to shut down. |
| 919 if (IsOnSwappedOutList(pending_render_view_host)) { | 949 if (IsOnSwappedOutList(pending_render_view_host)) { |
| 920 // Any currently suspended navigations are no longer needed. | 950 // Any currently suspended navigations are no longer needed. |
| 921 pending_render_view_host->CancelSuspendedNavigations(); | 951 pending_render_view_host->CancelSuspendedNavigations(); |
| 922 | 952 |
| 923 // We can pass -1,-1 because there is no pending response in the | 953 pending_render_view_host->SwapOut(); |
| 924 // ResourceDispatcherHost to unpause. | |
| 925 pending_render_view_host->SwapOut(-1, -1); | |
| 926 } else { | 954 } else { |
| 927 // We won't be coming back, so shut this one down. | 955 // We won't be coming back, so shut this one down. |
| 928 pending_render_view_host->Shutdown(); | 956 pending_render_view_host->Shutdown(); |
| 929 } | 957 } |
| 930 | 958 |
| 931 pending_web_ui_.reset(); | 959 pending_web_ui_.reset(); |
| 932 pending_and_current_web_ui_.reset(); | 960 pending_and_current_web_ui_.reset(); |
| 933 } | 961 } |
| 934 | 962 |
| 935 void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) { | 963 void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 975 RenderViewHostImpl* RenderViewHostManager::GetSwappedOutRenderViewHost( | 1003 RenderViewHostImpl* RenderViewHostManager::GetSwappedOutRenderViewHost( |
| 976 SiteInstance* instance) { | 1004 SiteInstance* instance) { |
| 977 RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId()); | 1005 RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId()); |
| 978 if (iter != swapped_out_hosts_.end()) | 1006 if (iter != swapped_out_hosts_.end()) |
| 979 return iter->second; | 1007 return iter->second; |
| 980 | 1008 |
| 981 return NULL; | 1009 return NULL; |
| 982 } | 1010 } |
| 983 | 1011 |
| 984 } // namespace content | 1012 } // namespace content |
| OLD | NEW |