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