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> |
11 | 11 |
12 #include "base/i18n/rtl.h" | 12 #include "base/i18n/rtl.h" |
13 #include "base/json/json_reader.h" | 13 #include "base/json/json_reader.h" |
14 #include "base/json/json_writer.h" | 14 #include "base/json/json_writer.h" |
15 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
16 #include "base/metrics/histogram.h" | |
16 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
17 #include "base/string_util.h" | 18 #include "base/string_util.h" |
18 #include "base/time.h" | 19 #include "base/time.h" |
19 #include "base/utf_string_conversions.h" | 20 #include "base/utf_string_conversions.h" |
20 #include "base/values.h" | 21 #include "base/values.h" |
21 #include "content/browser/accessibility/browser_accessibility_state_impl.h" | 22 #include "content/browser/accessibility/browser_accessibility_state_impl.h" |
22 #include "content/browser/child_process_security_policy_impl.h" | 23 #include "content/browser/child_process_security_policy_impl.h" |
23 #include "content/browser/cross_site_request_manager.h" | 24 #include "content/browser/cross_site_request_manager.h" |
24 #include "content/browser/dom_storage/session_storage_namespace_impl.h" | 25 #include "content/browser/dom_storage/session_storage_namespace_impl.h" |
25 #include "content/browser/gpu/gpu_surface_tracker.h" | 26 #include "content/browser/gpu/gpu_surface_tracker.h" |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 waiting_for_drag_context_response_(false), | 160 waiting_for_drag_context_response_(false), |
160 enabled_bindings_(0), | 161 enabled_bindings_(0), |
161 pending_request_id_(-1), | 162 pending_request_id_(-1), |
162 navigations_suspended_(false), | 163 navigations_suspended_(false), |
163 suspended_nav_message_(NULL), | 164 suspended_nav_message_(NULL), |
164 is_swapped_out_(swapped_out), | 165 is_swapped_out_(swapped_out), |
165 run_modal_reply_msg_(NULL), | 166 run_modal_reply_msg_(NULL), |
166 run_modal_opener_id_(MSG_ROUTING_NONE), | 167 run_modal_opener_id_(MSG_ROUTING_NONE), |
167 is_waiting_for_beforeunload_ack_(false), | 168 is_waiting_for_beforeunload_ack_(false), |
168 is_waiting_for_unload_ack_(false), | 169 is_waiting_for_unload_ack_(false), |
170 has_timed_out_on_unload_(false), | |
169 unload_ack_is_for_cross_site_transition_(false), | 171 unload_ack_is_for_cross_site_transition_(false), |
170 are_javascript_messages_suppressed_(false), | 172 are_javascript_messages_suppressed_(false), |
171 sudden_termination_allowed_(false), | 173 sudden_termination_allowed_(false), |
172 session_storage_namespace_( | 174 session_storage_namespace_( |
173 static_cast<SessionStorageNamespaceImpl*>(session_storage)), | 175 static_cast<SessionStorageNamespaceImpl*>(session_storage)), |
174 save_accessibility_tree_for_testing_(false), | 176 save_accessibility_tree_for_testing_(false), |
175 render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING) { | 177 render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING) { |
176 DCHECK(session_storage_namespace_); | 178 DCHECK(session_storage_namespace_); |
177 DCHECK(instance_); | 179 DCHECK(instance_); |
178 CHECK(delegate_); // http://crbug.com/82827 | 180 CHECK(delegate_); // http://crbug.com/82827 |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
393 // (if there was a cross-site "close" request pending when the user clicked | 395 // (if there was a cross-site "close" request pending when the user clicked |
394 // the close button). We want to keep the "for cross site" flag only if | 396 // the close button). We want to keep the "for cross site" flag only if |
395 // both the old and the new ones are also for cross site. | 397 // both the old and the new ones are also for cross site. |
396 unload_ack_is_for_cross_site_transition_ = | 398 unload_ack_is_for_cross_site_transition_ = |
397 unload_ack_is_for_cross_site_transition_ && for_cross_site_transition; | 399 unload_ack_is_for_cross_site_transition_ && for_cross_site_transition; |
398 } else { | 400 } else { |
399 // Start the hang monitor in case the renderer hangs in the beforeunload | 401 // Start the hang monitor in case the renderer hangs in the beforeunload |
400 // handler. | 402 // handler. |
401 is_waiting_for_beforeunload_ack_ = true; | 403 is_waiting_for_beforeunload_ack_ = true; |
402 unload_ack_is_for_cross_site_transition_ = for_cross_site_transition; | 404 unload_ack_is_for_cross_site_transition_ = for_cross_site_transition; |
405 // Increment the in-flight event count, to ensure that input events won't | |
406 // cancel the timeout timer. | |
407 increment_in_flight_event_count(); | |
403 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 408 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
404 send_should_close_start_time_ = base::TimeTicks::Now(); | 409 send_should_close_start_time_ = base::TimeTicks::Now(); |
405 Send(new ViewMsg_ShouldClose(GetRoutingID())); | 410 Send(new ViewMsg_ShouldClose(GetRoutingID())); |
406 } | 411 } |
407 } | 412 } |
408 | 413 |
409 void RenderViewHostImpl::SwapOut(int new_render_process_host_id, | 414 void RenderViewHostImpl::SwapOut(int new_render_process_host_id, |
410 int new_request_id) { | 415 int new_request_id) { |
411 // This will be set back to false in OnSwapOutACK, just before we replace | 416 // This will be set back to false in OnSwapOutACK, just before we replace |
412 // this RVH with the pending RVH. | 417 // this RVH with the pending RVH. |
413 is_waiting_for_unload_ack_ = true; | 418 is_waiting_for_unload_ack_ = true; |
414 // Start the hang monitor in case the renderer hangs in the unload handler. | 419 // Start the hang monitor in case the renderer hangs in the unload handler. |
420 // Increment the in-flight event count, to ensure that input events won't | |
421 // cancel the timeout timer. | |
422 increment_in_flight_event_count(); | |
415 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 423 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
416 | 424 |
417 ViewMsg_SwapOut_Params params; | 425 ViewMsg_SwapOut_Params params; |
418 params.closing_process_id = GetProcess()->GetID(); | 426 params.closing_process_id = GetProcess()->GetID(); |
419 params.closing_route_id = GetRoutingID(); | 427 params.closing_route_id = GetRoutingID(); |
420 params.new_render_process_host_id = new_render_process_host_id; | 428 params.new_render_process_host_id = new_render_process_host_id; |
421 params.new_request_id = new_request_id; | 429 params.new_request_id = new_request_id; |
422 if (IsRenderViewLive()) { | 430 if (IsRenderViewLive()) { |
423 Send(new ViewMsg_SwapOut(GetRoutingID(), params)); | 431 Send(new ViewMsg_SwapOut(GetRoutingID(), params)); |
424 } else { | 432 } else { |
425 // This RenderViewHost doesn't have a live renderer, so just skip the unload | 433 // This RenderViewHost doesn't have a live renderer, so just skip the unload |
426 // event. We must notify the ResourceDispatcherHost on the IO thread, | 434 // event. We must notify the ResourceDispatcherHost on the IO thread, |
427 // which we will do through the RenderProcessHost's widget helper. | 435 // which we will do through the RenderProcessHost's widget helper. |
428 GetProcess()->CrossSiteSwapOutACK(params); | 436 GetProcess()->SimulateSwapOutACK(params); |
429 } | 437 } |
430 } | 438 } |
431 | 439 |
432 void RenderViewHostImpl::OnSwapOutACK() { | 440 void RenderViewHostImpl::OnSwapOutACK(bool timed_out) { |
433 // Stop the hang monitor now that the unload handler has finished. | 441 // Stop the hang monitor now that the unload handler has finished. |
442 decrement_in_flight_event_count(); | |
434 StopHangMonitorTimeout(); | 443 StopHangMonitorTimeout(); |
435 is_waiting_for_unload_ack_ = false; | 444 is_waiting_for_unload_ack_ = false; |
445 has_timed_out_on_unload_ = timed_out; | |
436 delegate_->SwappedOut(this); | 446 delegate_->SwappedOut(this); |
437 } | 447 } |
438 | 448 |
439 void RenderViewHostImpl::WasSwappedOut() { | 449 void RenderViewHostImpl::WasSwappedOut() { |
440 // Don't bother reporting hung state anymore. | 450 // Don't bother reporting hung state anymore. |
441 StopHangMonitorTimeout(); | 451 StopHangMonitorTimeout(); |
442 | 452 |
453 // If we have timed out on running the unload handler, we consider | |
454 // the process hung and we should terminate it if there are no other tabs | |
455 // using the process. If there are other views using this process, the | |
456 // unresponsive renderer timeout will catch it. | |
457 bool hung = has_timed_out_on_unload_; | |
458 | |
443 // Now that we're no longer the active RVH in the tab, start filtering out | 459 // Now that we're no longer the active RVH in the tab, start filtering out |
444 // most IPC messages. Usually the renderer will have stopped sending | 460 // most IPC messages. Usually the renderer will have stopped sending |
445 // messages as of OnSwapOutACK. However, we may have timed out waiting | 461 // messages as of OnSwapOutACK. However, we may have timed out waiting |
446 // for that message, and additional IPC messages may keep streaming in. | 462 // for that message, and additional IPC messages may keep streaming in. |
447 // We filter them out, as long as that won't cause problems (e.g., we | 463 // We filter them out, as long as that won't cause problems (e.g., we |
448 // still allow synchronous messages through). | 464 // still allow synchronous messages through). |
449 SetSwappedOut(true); | 465 SetSwappedOut(true); |
450 | 466 |
467 // If we are not running the renderer in process and no other tab is using | |
468 // the hung process, consider it eligible to be killed, assuming it is a real | |
469 // process (unit tests don't have real processes). | |
470 if (hung) { | |
471 base::ProcessHandle process_handle = GetProcess()->GetHandle(); | |
472 int views = 0; | |
473 | |
474 // Count the number of widget hosts for the process, which is equivalent to | |
475 // views using the process as of this writing. | |
476 content::RenderProcessHost::RenderWidgetHostsIterator iter( | |
477 GetProcess()->GetRenderWidgetHostsIterator()); | |
478 for (; !iter.IsAtEnd(); iter.Advance()) | |
479 ++views; | |
480 | |
481 if (!content::RenderProcessHost::run_renderer_in_process() && | |
482 process_handle && views <= 1) { | |
483 // The process can safely be terminated, only if WebContents sets | |
484 // SuddenTerminationAllowed, which indicates that the timer has expired. | |
485 // This is not the case if we load data URLs or about:blank. The reason | |
486 // is that there is no network requests and this code is hit without | |
Charlie Reis
2012/09/13 21:50:20
nit: there is -> those have
nasko
2012/09/13 22:09:30
Done.
| |
487 // setting the unresponsiveness timer. This allows a corner case where a | |
488 // navigation to a data URL will leave a process running, if the | |
489 // beforeunload handler completes fine, but the unload handler hangs. | |
490 // At this time, the complexity to solve this edge case is not worthwhile. | |
491 if (SuddenTerminationAllowed()) { | |
492 // We should kill the process, but for now, just log the data so we can | |
493 // diagnose the kill rate and investigate if separate timer is needed. | |
494 // http://crbug.com/104346. | |
495 | |
496 // Log a histogram point to help us diagnose how many of those kills | |
497 // we have performed. 1 is the enum value for RendererType Normal for | |
498 // the histogram. | |
499 UMA_HISTOGRAM_PERCENTAGE( | |
500 "BrowserRenderProcessHost.ChildKillsUnresponsive", 1); | |
501 } | |
502 } | |
503 } | |
504 | |
451 // Inform the renderer that it can exit if no one else is using it. | 505 // Inform the renderer that it can exit if no one else is using it. |
452 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); | 506 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); |
453 } | 507 } |
454 | 508 |
455 void RenderViewHostImpl::ClosePage() { | 509 void RenderViewHostImpl::ClosePage() { |
456 // Start the hang monitor in case the renderer hangs in the unload handler. | 510 // Start the hang monitor in case the renderer hangs in the unload handler. |
457 is_waiting_for_unload_ack_ = true; | 511 is_waiting_for_unload_ack_ = true; |
458 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 512 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
459 | 513 |
460 if (IsRenderViewLive()) { | 514 if (IsRenderViewLive()) { |
515 // Since we are sending an IPC message to the renderer, increase the event | |
516 // count to prevent the hang monitor timeout from being stopped by input | |
517 // event acknowledgements. | |
518 increment_in_flight_event_count(); | |
519 | |
461 // TODO(creis): Should this be moved to Shutdown? It may not be called for | 520 // TODO(creis): Should this be moved to Shutdown? It may not be called for |
462 // RenderViewHosts that have been swapped out. | 521 // RenderViewHosts that have been swapped out. |
463 content::NotificationService::current()->Notify( | 522 content::NotificationService::current()->Notify( |
464 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, | 523 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, |
465 content::Source<RenderViewHost>(this), | 524 content::Source<RenderViewHost>(this), |
466 content::NotificationService::NoDetails()); | 525 content::NotificationService::NoDetails()); |
467 | 526 |
468 Send(new ViewMsg_ClosePage(GetRoutingID())); | 527 Send(new ViewMsg_ClosePage(GetRoutingID())); |
469 } else { | 528 } else { |
470 // This RenderViewHost doesn't have a live renderer, so just skip the unload | 529 // This RenderViewHost doesn't have a live renderer, so just skip the unload |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
675 loop->Run(); | 734 loop->Run(); |
676 return observer.value()->DeepCopy(); | 735 return observer.value()->DeepCopy(); |
677 } | 736 } |
678 | 737 |
679 void RenderViewHostImpl::JavaScriptDialogClosed(IPC::Message* reply_msg, | 738 void RenderViewHostImpl::JavaScriptDialogClosed(IPC::Message* reply_msg, |
680 bool success, | 739 bool success, |
681 const string16& user_input) { | 740 const string16& user_input) { |
682 GetProcess()->SetIgnoreInputEvents(false); | 741 GetProcess()->SetIgnoreInputEvents(false); |
683 bool is_waiting = | 742 bool is_waiting = |
684 is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_; | 743 is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_; |
744 | |
745 // If we are executing as part of (before)unload event handling, we don't | |
746 // want to use the regular hung_renderer_delay_ms_ if the user has agreed to | |
747 // leave the current page. In this case, use the regular timeout value used | |
748 // during the (before)unload handling. | |
685 if (is_waiting) | 749 if (is_waiting) |
686 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 750 StartHangMonitorTimeout(TimeDelta::FromMilliseconds( |
751 success ? kUnloadTimeoutMS : hung_renderer_delay_ms_)); | |
Charlie Reis
2012/09/13 21:50:20
nit: Needs braces.
nasko
2012/09/13 22:09:30
Done.
| |
687 | 752 |
688 ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, | 753 ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, |
689 success, user_input); | 754 success, user_input); |
690 Send(reply_msg); | 755 Send(reply_msg); |
691 | 756 |
692 // If we are waiting for an unload or beforeunload ack and the user has | 757 // If we are waiting for an unload or beforeunload ack and the user has |
693 // suppressed messages, kill the tab immediately; a page that's spamming | 758 // suppressed messages, kill the tab immediately; a page that's spamming |
694 // alerts in onbeforeunload is presumably malicious, so there's no point in | 759 // alerts in onbeforeunload is presumably malicious, so there's no point in |
695 // continuing to run its script and dragging out the process. | 760 // continuing to run its script and dragging out the process. |
696 // This must be done after sending the reply since RenderView can't close | 761 // This must be done after sending the reply since RenderView can't close |
(...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1454 } | 1519 } |
1455 | 1520 |
1456 void RenderViewHostImpl::OnUserGesture() { | 1521 void RenderViewHostImpl::OnUserGesture() { |
1457 delegate_->OnUserGesture(); | 1522 delegate_->OnUserGesture(); |
1458 } | 1523 } |
1459 | 1524 |
1460 void RenderViewHostImpl::OnMsgShouldCloseACK( | 1525 void RenderViewHostImpl::OnMsgShouldCloseACK( |
1461 bool proceed, | 1526 bool proceed, |
1462 const base::TimeTicks& renderer_before_unload_start_time, | 1527 const base::TimeTicks& renderer_before_unload_start_time, |
1463 const base::TimeTicks& renderer_before_unload_end_time) { | 1528 const base::TimeTicks& renderer_before_unload_end_time) { |
1529 decrement_in_flight_event_count(); | |
1464 StopHangMonitorTimeout(); | 1530 StopHangMonitorTimeout(); |
1465 // If this renderer navigated while the beforeunload request was in flight, we | 1531 // If this renderer navigated while the beforeunload request was in flight, we |
1466 // may have cleared this state in OnMsgNavigate, in which case we can ignore | 1532 // may have cleared this state in OnMsgNavigate, in which case we can ignore |
1467 // this message. | 1533 // this message. |
1468 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) | 1534 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) |
1469 return; | 1535 return; |
1470 | 1536 |
1471 is_waiting_for_beforeunload_ack_ = false; | 1537 is_waiting_for_beforeunload_ack_ = false; |
1472 | 1538 |
1473 RenderViewHostDelegate::RendererManagement* management_delegate = | 1539 RenderViewHostDelegate::RendererManagement* management_delegate = |
(...skipping 21 matching lines...) Expand all Loading... | |
1495 unload_ack_is_for_cross_site_transition_, proceed, | 1561 unload_ack_is_for_cross_site_transition_, proceed, |
1496 before_unload_end_time); | 1562 before_unload_end_time); |
1497 } | 1563 } |
1498 | 1564 |
1499 // If canceled, notify the delegate to cancel its pending navigation entry. | 1565 // If canceled, notify the delegate to cancel its pending navigation entry. |
1500 if (!proceed) | 1566 if (!proceed) |
1501 delegate_->DidCancelLoading(); | 1567 delegate_->DidCancelLoading(); |
1502 } | 1568 } |
1503 | 1569 |
1504 void RenderViewHostImpl::OnMsgClosePageACK() { | 1570 void RenderViewHostImpl::OnMsgClosePageACK() { |
1571 decrement_in_flight_event_count(); | |
1505 ClosePageIgnoringUnloadEvents(); | 1572 ClosePageIgnoringUnloadEvents(); |
1506 } | 1573 } |
1507 | 1574 |
1508 void RenderViewHostImpl::NotifyRendererUnresponsive() { | 1575 void RenderViewHostImpl::NotifyRendererUnresponsive() { |
1509 delegate_->RendererUnresponsive( | 1576 delegate_->RendererUnresponsive( |
1510 this, is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_); | 1577 this, is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_); |
1511 } | 1578 } |
1512 | 1579 |
1513 void RenderViewHostImpl::NotifyRendererResponsive() { | 1580 void RenderViewHostImpl::NotifyRendererResponsive() { |
1514 delegate_->RendererResponsive(this); | 1581 delegate_->RendererResponsive(this); |
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1914 } | 1981 } |
1915 | 1982 |
1916 void RenderViewHostImpl::SetSwappedOut(bool is_swapped_out) { | 1983 void RenderViewHostImpl::SetSwappedOut(bool is_swapped_out) { |
1917 is_swapped_out_ = is_swapped_out; | 1984 is_swapped_out_ = is_swapped_out; |
1918 | 1985 |
1919 // Whenever we change swap out state, we should not be waiting for | 1986 // Whenever we change swap out state, we should not be waiting for |
1920 // beforeunload or unload acks. We clear them here to be safe, since they | 1987 // beforeunload or unload acks. We clear them here to be safe, since they |
1921 // can cause navigations to be ignored in OnMsgNavigate. | 1988 // can cause navigations to be ignored in OnMsgNavigate. |
1922 is_waiting_for_beforeunload_ack_ = false; | 1989 is_waiting_for_beforeunload_ack_ = false; |
1923 is_waiting_for_unload_ack_ = false; | 1990 is_waiting_for_unload_ack_ = false; |
1991 has_timed_out_on_unload_ = false; | |
1924 } | 1992 } |
1925 | 1993 |
1926 void RenderViewHostImpl::ClearPowerSaveBlockers() { | 1994 void RenderViewHostImpl::ClearPowerSaveBlockers() { |
1927 STLDeleteValues(&power_save_blockers_); | 1995 STLDeleteValues(&power_save_blockers_); |
1928 } | 1996 } |
1929 | 1997 |
1930 } // namespace content | 1998 } // namespace content |
OLD | NEW |