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 |