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

Side by Side Diff: content/browser/renderer_host/render_view_host_impl.cc

Issue 9514016: Fixing a problem, where a hung renderer process is not killed when navigating away (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Final cleanup update. Created 8 years, 9 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 (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
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
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
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
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
OLDNEW
« no previous file with comments | « content/browser/renderer_host/render_view_host_impl.h ('k') | content/browser/renderer_host/render_widget_host_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698