| 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/renderer_host/render_view_host_impl.h" | 5 #include "content/browser/renderer_host/render_view_host_impl.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 #include "content/common/view_messages.h" | 34 #include "content/common/view_messages.h" |
| 35 #include "content/port/browser/render_widget_host_view_port.h" | 35 #include "content/port/browser/render_widget_host_view_port.h" |
| 36 #include "content/public/browser/browser_context.h" | 36 #include "content/public/browser/browser_context.h" |
| 37 #include "content/public/browser/browser_message_filter.h" | 37 #include "content/public/browser/browser_message_filter.h" |
| 38 #include "content/public/browser/content_browser_client.h" | 38 #include "content/public/browser/content_browser_client.h" |
| 39 #include "content/public/browser/dom_operation_notification_details.h" | 39 #include "content/public/browser/dom_operation_notification_details.h" |
| 40 #include "content/public/browser/native_web_keyboard_event.h" | 40 #include "content/public/browser/native_web_keyboard_event.h" |
| 41 #include "content/public/browser/notification_details.h" | 41 #include "content/public/browser/notification_details.h" |
| 42 #include "content/public/browser/notification_service.h" | 42 #include "content/public/browser/notification_service.h" |
| 43 #include "content/public/browser/notification_types.h" | 43 #include "content/public/browser/notification_types.h" |
| 44 #include "content/public/browser/render_process_host.h" |
| 44 #include "content/public/browser/render_view_host_delegate.h" | 45 #include "content/public/browser/render_view_host_delegate.h" |
| 45 #include "content/public/browser/render_view_host_observer.h" | 46 #include "content/public/browser/render_view_host_observer.h" |
| 46 #include "content/public/browser/user_metrics.h" | 47 #include "content/public/browser/user_metrics.h" |
| 47 #include "content/public/common/bindings_policy.h" | 48 #include "content/public/common/bindings_policy.h" |
| 48 #include "content/public/common/content_constants.h" | 49 #include "content/public/common/content_constants.h" |
| 49 #include "content/public/common/content_switches.h" | 50 #include "content/public/common/content_switches.h" |
| 50 #include "content/public/common/context_menu_params.h" | 51 #include "content/public/common/context_menu_params.h" |
| 51 #include "content/public/common/result_codes.h" | 52 #include "content/public/common/result_codes.h" |
| 52 #include "content/public/common/selected_file_info.h" | 53 #include "content/public/common/selected_file_info.h" |
| 53 #include "content/public/common/url_constants.h" | 54 #include "content/public/common/url_constants.h" |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 } else { | 413 } else { |
| 413 // This RenderViewHost doesn't have a live renderer, so just skip the unload | 414 // This RenderViewHost doesn't have a live renderer, so just skip the unload |
| 414 // event. We must notify the ResourceDispatcherHost on the IO thread, | 415 // event. We must notify the ResourceDispatcherHost on the IO thread, |
| 415 // which we will do through the RenderProcessHost's widget helper. | 416 // which we will do through the RenderProcessHost's widget helper. |
| 416 GetProcess()->CrossSiteSwapOutACK(params); | 417 GetProcess()->CrossSiteSwapOutACK(params); |
| 417 } | 418 } |
| 418 } | 419 } |
| 419 | 420 |
| 420 void RenderViewHostImpl::OnSwapOutACK() { | 421 void RenderViewHostImpl::OnSwapOutACK() { |
| 421 // Stop the hang monitor now that the unload handler has finished. | 422 // Stop the hang monitor now that the unload handler has finished. |
| 423 is_waiting_for_unload_ack_ = false; |
| 422 StopHangMonitorTimeout(); | 424 StopHangMonitorTimeout(); |
| 423 is_waiting_for_unload_ack_ = false; | |
| 424 delegate_->SwappedOut(this); | 425 delegate_->SwappedOut(this); |
| 425 } | 426 } |
| 426 | 427 |
| 427 void RenderViewHostImpl::WasSwappedOut() { | 428 void RenderViewHostImpl::WasSwappedOut() { |
| 428 // Don't bother reporting hung state anymore. | 429 // If we are still waiting on the unload handler to be run, we consider |
| 429 StopHangMonitorTimeout(); | 430 // the process hung and we should terminate it if there are no other tabs |
| 431 // using the process. If there are other views using this process, the |
| 432 // unresponsive renderer timeout will catch it. |
| 433 bool hung = is_waiting_for_unload_ack_; |
| 430 | 434 |
| 431 // Now that we're no longer the active RVH in the tab, start filtering out | 435 // Now that we're no longer the active RVH in the tab, start filtering out |
| 432 // most IPC messages. Usually the renderer will have stopped sending | 436 // most IPC messages. Usually the renderer will have stopped sending |
| 433 // messages as of OnSwapOutACK. However, we may have timed out waiting | 437 // messages as of OnSwapOutACK. However, we may have timed out waiting |
| 434 // for that message, and additional IPC messages may keep streaming in. | 438 // for that message, and additional IPC messages may keep streaming in. |
| 435 // We filter them out, as long as that won't cause problems (e.g., we | 439 // We filter them out, as long as that won't cause problems (e.g., we |
| 436 // still allow synchronous messages through). | 440 // still allow synchronous messages through). |
| 437 SetSwappedOut(true); | 441 SetSwappedOut(true); |
| 438 | 442 |
| 443 // Don't bother reporting hung state anymore. |
| 444 StopHangMonitorTimeout(); |
| 445 |
| 446 // If we are not running the renderer in process and no other tab is using |
| 447 // the hung process, kill it, assuming it is a real process (unit tests don't |
| 448 // have real processes). |
| 449 if (hung) { |
| 450 base::ProcessHandle process_handle = GetProcess()->GetHandle(); |
| 451 int views = 0; |
| 452 |
| 453 // Count the number of listeners for the process, which is equivalent to |
| 454 // views using the process as of this writing. |
| 455 content::RenderProcessHost::RenderWidgetHostsIterator iter( |
| 456 GetProcess()->GetRenderWidgetHostsIterator()); |
| 457 for (; !iter.IsAtEnd(); iter.Advance()) |
| 458 ++views; |
| 459 |
| 460 if (!content::RenderProcessHost::run_renderer_in_process() && |
| 461 process_handle && views <= 1) { |
| 462 // We expect the delegate for this RVH to be TabContents, as it is the |
| 463 // only class that swaps out render view hosts on navigation. |
| 464 DCHECK(delegate_->GetRenderViewType() == content::VIEW_TYPE_TAB_CONTENTS); |
| 465 |
| 466 // Kill the process only if TabContents sets SuddenTerminationAllowed, |
| 467 // which indicates that the timer has expired. |
| 468 // This is not the case if we load data URLs or about:blank. The reason |
| 469 // is that there is no network requests and this code is hit without |
| 470 // setting the unresponsiveness timer. This allows a corner case where a |
| 471 // navigation to a data URL will leave a process running, if the |
| 472 // beforeunload handler completes fine, but the unload handler hangs. |
| 473 // At this time, the complexity to solve this edge case is not worthwhile. |
| 474 if (SuddenTerminationAllowed()) { |
| 475 base::KillProcess(process_handle, content::RESULT_CODE_HUNG, false); |
| 476 } |
| 477 } |
| 478 } |
| 479 |
| 439 // Inform the renderer that it can exit if no one else is using it. | 480 // Inform the renderer that it can exit if no one else is using it. |
| 440 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); | 481 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); |
| 441 } | 482 } |
| 442 | 483 |
| 443 void RenderViewHostImpl::ClosePage() { | 484 void RenderViewHostImpl::ClosePage() { |
| 444 // Start the hang monitor in case the renderer hangs in the unload handler. | 485 // Start the hang monitor in case the renderer hangs in the unload handler. |
| 445 is_waiting_for_unload_ack_ = true; | 486 is_waiting_for_unload_ack_ = true; |
| 446 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 487 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
| 447 | 488 |
| 448 if (IsRenderViewLive()) { | 489 if (IsRenderViewLive()) { |
| 449 // TODO(creis): Should this be moved to Shutdown? It may not be called for | 490 // TODO(creis): Should this be moved to Shutdown? It may not be called for |
| 450 // RenderViewHosts that have been swapped out. | 491 // RenderViewHosts that have been swapped out. |
| 451 content::NotificationService::current()->Notify( | 492 content::NotificationService::current()->Notify( |
| 452 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, | 493 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, |
| 453 content::Source<RenderViewHost>(this), | 494 content::Source<RenderViewHost>(this), |
| 454 content::NotificationService::NoDetails()); | 495 content::NotificationService::NoDetails()); |
| 455 | 496 |
| 456 Send(new ViewMsg_ClosePage(GetRoutingID())); | 497 Send(new ViewMsg_ClosePage(GetRoutingID())); |
| 457 } else { | 498 } else { |
| 458 // This RenderViewHost doesn't have a live renderer, so just skip the unload | 499 // This RenderViewHost doesn't have a live renderer, so just skip the unload |
| 459 // event and close the page. | 500 // event and close the page. |
| 460 ClosePageIgnoringUnloadEvents(); | 501 ClosePageIgnoringUnloadEvents(); |
| 461 } | 502 } |
| 462 } | 503 } |
| 463 | 504 |
| 464 void RenderViewHostImpl::ClosePageIgnoringUnloadEvents() { | 505 void RenderViewHostImpl::ClosePageIgnoringUnloadEvents() { |
| 465 StopHangMonitorTimeout(); | |
| 466 is_waiting_for_beforeunload_ack_ = false; | 506 is_waiting_for_beforeunload_ack_ = false; |
| 467 is_waiting_for_unload_ack_ = false; | 507 is_waiting_for_unload_ack_ = false; |
| 508 StopHangMonitorTimeout(); |
| 468 | 509 |
| 469 sudden_termination_allowed_ = true; | 510 sudden_termination_allowed_ = true; |
| 470 delegate_->Close(this); | 511 delegate_->Close(this); |
| 471 } | 512 } |
| 472 | 513 |
| 473 void RenderViewHostImpl::SetHasPendingCrossSiteRequest(bool has_pending_request, | 514 void RenderViewHostImpl::SetHasPendingCrossSiteRequest(bool has_pending_request, |
| 474 int request_id) { | 515 int request_id) { |
| 475 CrossSiteRequestManager::GetInstance()->SetHasPendingCrossSiteRequest( | 516 CrossSiteRequestManager::GetInstance()->SetHasPendingCrossSiteRequest( |
| 476 GetProcess()->GetID(), GetRoutingID(), has_pending_request); | 517 GetProcess()->GetID(), GetRoutingID(), has_pending_request); |
| 477 pending_request_id_ = request_id; | 518 pending_request_id_ = request_id; |
| (...skipping 844 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1322 } | 1363 } |
| 1323 | 1364 |
| 1324 void RenderViewHostImpl::OnUserGesture() { | 1365 void RenderViewHostImpl::OnUserGesture() { |
| 1325 delegate_->OnUserGesture(); | 1366 delegate_->OnUserGesture(); |
| 1326 } | 1367 } |
| 1327 | 1368 |
| 1328 void RenderViewHostImpl::OnMsgShouldCloseACK( | 1369 void RenderViewHostImpl::OnMsgShouldCloseACK( |
| 1329 bool proceed, | 1370 bool proceed, |
| 1330 const base::TimeTicks& renderer_before_unload_start_time, | 1371 const base::TimeTicks& renderer_before_unload_start_time, |
| 1331 const base::TimeTicks& renderer_before_unload_end_time) { | 1372 const base::TimeTicks& renderer_before_unload_end_time) { |
| 1332 StopHangMonitorTimeout(); | |
| 1333 // If this renderer navigated while the beforeunload request was in flight, we | 1373 // If this renderer navigated while the beforeunload request was in flight, we |
| 1334 // may have cleared this state in OnMsgNavigate, in which case we can ignore | 1374 // may have cleared this state in OnMsgNavigate, in which case we can ignore |
| 1335 // this message. | 1375 // this message. |
| 1336 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) | 1376 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) { |
| 1377 StopHangMonitorTimeout(); |
| 1337 return; | 1378 return; |
| 1379 } |
| 1338 | 1380 |
| 1339 is_waiting_for_beforeunload_ack_ = false; | 1381 is_waiting_for_beforeunload_ack_ = false; |
| 1382 StopHangMonitorTimeout(); |
| 1340 | 1383 |
| 1341 RenderViewHostDelegate::RendererManagement* management_delegate = | 1384 RenderViewHostDelegate::RendererManagement* management_delegate = |
| 1342 delegate_->GetRendererManagementDelegate(); | 1385 delegate_->GetRendererManagementDelegate(); |
| 1343 if (management_delegate) { | 1386 if (management_delegate) { |
| 1344 base::TimeTicks before_unload_end_time; | 1387 base::TimeTicks before_unload_end_time; |
| 1345 if (!send_should_close_start_time_.is_null() && | 1388 if (!send_should_close_start_time_.is_null() && |
| 1346 !renderer_before_unload_start_time.is_null() && | 1389 !renderer_before_unload_start_time.is_null() && |
| 1347 !renderer_before_unload_end_time.is_null()) { | 1390 !renderer_before_unload_end_time.is_null()) { |
| 1348 // When passing TimeTicks across process boundaries, we need to compensate | 1391 // When passing TimeTicks across process boundaries, we need to compensate |
| 1349 // for any skew between the processes. Here we are converting the | 1392 // for any skew between the processes. Here we are converting the |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1731 // beforeunload or unload acks. We clear them here to be safe, since they | 1774 // beforeunload or unload acks. We clear them here to be safe, since they |
| 1732 // can cause navigations to be ignored in OnMsgNavigate. | 1775 // can cause navigations to be ignored in OnMsgNavigate. |
| 1733 is_waiting_for_beforeunload_ack_ = false; | 1776 is_waiting_for_beforeunload_ack_ = false; |
| 1734 is_waiting_for_unload_ack_ = false; | 1777 is_waiting_for_unload_ack_ = false; |
| 1735 } | 1778 } |
| 1736 | 1779 |
| 1737 void RenderViewHostImpl::ClearPowerSaveBlockers() { | 1780 void RenderViewHostImpl::ClearPowerSaveBlockers() { |
| 1738 STLDeleteValues(&power_save_blockers_); | 1781 STLDeleteValues(&power_save_blockers_); |
| 1739 } | 1782 } |
| 1740 | 1783 |
| 1784 // During cross-site navigation, we have timeouts on beforeunload and unload |
| 1785 // handler processing. If we are asked to stop that timeout monitoring while |
| 1786 // we have an outstanding handler processing, we must not stop it. If we do, |
| 1787 // then slow or unresponsive renderer process will hang the navigation as there |
| 1788 // will be no way for us to detect it. Stopping of the timer is most frequently |
| 1789 // caused by input events, which restart the hang detection timeout. |
| 1790 void RenderViewHostImpl::StopHangMonitorTimeout() { |
| 1791 if (is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_) |
| 1792 return; |
| 1793 |
| 1794 RenderWidgetHostImpl::StopHangMonitorTimeout(); |
| 1795 } |
| 1796 |
| 1741 } // namespace content | 1797 } // namespace content |
| OLD | NEW |