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/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/i18n/rtl.h" | 13 #include "base/i18n/rtl.h" |
14 #include "base/json/json_reader.h" | 14 #include "base/json/json_reader.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/child_process_security_policy_impl.h" | 22 #include "content/browser/child_process_security_policy_impl.h" |
22 #include "content/browser/cross_site_request_manager.h" | 23 #include "content/browser/cross_site_request_manager.h" |
23 #include "content/browser/gpu/gpu_surface_tracker.h" | 24 #include "content/browser/gpu/gpu_surface_tracker.h" |
24 #include "content/browser/host_zoom_map_impl.h" | 25 #include "content/browser/host_zoom_map_impl.h" |
25 #include "content/browser/in_process_webkit/dom_storage_context_impl.h" | 26 #include "content/browser/in_process_webkit/dom_storage_context_impl.h" |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 waiting_for_drag_context_response_(false), | 136 waiting_for_drag_context_response_(false), |
136 enabled_bindings_(0), | 137 enabled_bindings_(0), |
137 guest_(false), | 138 guest_(false), |
138 pending_request_id_(-1), | 139 pending_request_id_(-1), |
139 navigations_suspended_(false), | 140 navigations_suspended_(false), |
140 suspended_nav_message_(NULL), | 141 suspended_nav_message_(NULL), |
141 is_swapped_out_(false), | 142 is_swapped_out_(false), |
142 run_modal_reply_msg_(NULL), | 143 run_modal_reply_msg_(NULL), |
143 is_waiting_for_beforeunload_ack_(false), | 144 is_waiting_for_beforeunload_ack_(false), |
144 is_waiting_for_unload_ack_(false), | 145 is_waiting_for_unload_ack_(false), |
| 146 has_timed_out_on_unload_(false), |
145 unload_ack_is_for_cross_site_transition_(false), | 147 unload_ack_is_for_cross_site_transition_(false), |
146 are_javascript_messages_suppressed_(false), | 148 are_javascript_messages_suppressed_(false), |
147 sudden_termination_allowed_(false), | 149 sudden_termination_allowed_(false), |
148 session_storage_namespace_( | 150 session_storage_namespace_( |
149 static_cast<SessionStorageNamespaceImpl*>(session_storage)), | 151 static_cast<SessionStorageNamespaceImpl*>(session_storage)), |
150 save_accessibility_tree_for_testing_(false), | 152 save_accessibility_tree_for_testing_(false), |
151 send_accessibility_updated_notifications_(false), | 153 send_accessibility_updated_notifications_(false), |
152 render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING) { | 154 render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING) { |
153 if (!session_storage_namespace_) { | 155 if (!session_storage_namespace_) { |
154 DOMStorageContext* dom_storage_context = | 156 DOMStorageContext* dom_storage_context = |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 // (if there was a cross-site "close" request pending when the user clicked | 379 // (if there was a cross-site "close" request pending when the user clicked |
378 // the close button). We want to keep the "for cross site" flag only if | 380 // the close button). We want to keep the "for cross site" flag only if |
379 // both the old and the new ones are also for cross site. | 381 // both the old and the new ones are also for cross site. |
380 unload_ack_is_for_cross_site_transition_ = | 382 unload_ack_is_for_cross_site_transition_ = |
381 unload_ack_is_for_cross_site_transition_ && for_cross_site_transition; | 383 unload_ack_is_for_cross_site_transition_ && for_cross_site_transition; |
382 } else { | 384 } else { |
383 // Start the hang monitor in case the renderer hangs in the beforeunload | 385 // Start the hang monitor in case the renderer hangs in the beforeunload |
384 // handler. | 386 // handler. |
385 is_waiting_for_beforeunload_ack_ = true; | 387 is_waiting_for_beforeunload_ack_ = true; |
386 unload_ack_is_for_cross_site_transition_ = for_cross_site_transition; | 388 unload_ack_is_for_cross_site_transition_ = for_cross_site_transition; |
| 389 // Increment the in-flight event count, to ensure that input events won't |
| 390 // cancel the timeout timer. |
| 391 increment_in_flight_event_count(); |
387 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 392 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
388 send_should_close_start_time_ = base::TimeTicks::Now(); | 393 send_should_close_start_time_ = base::TimeTicks::Now(); |
389 Send(new ViewMsg_ShouldClose(GetRoutingID())); | 394 Send(new ViewMsg_ShouldClose(GetRoutingID())); |
390 } | 395 } |
391 } | 396 } |
392 | 397 |
393 void RenderViewHostImpl::SwapOut(int new_render_process_host_id, | 398 void RenderViewHostImpl::SwapOut(int new_render_process_host_id, |
394 int new_request_id) { | 399 int new_request_id) { |
395 // This will be set back to false in OnSwapOutACK, just before we replace | 400 // This will be set back to false in OnSwapOutACK, just before we replace |
396 // this RVH with the pending RVH. | 401 // this RVH with the pending RVH. |
397 is_waiting_for_unload_ack_ = true; | 402 is_waiting_for_unload_ack_ = true; |
398 // Start the hang monitor in case the renderer hangs in the unload handler. | 403 // Start the hang monitor in case the renderer hangs in the unload handler. |
| 404 // Increment the in-flight event count, to ensure that input events won't |
| 405 // cancel the timeout timer. |
| 406 increment_in_flight_event_count(); |
399 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 407 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
400 | 408 |
401 ViewMsg_SwapOut_Params params; | 409 ViewMsg_SwapOut_Params params; |
402 params.closing_process_id = GetProcess()->GetID(); | 410 params.closing_process_id = GetProcess()->GetID(); |
403 params.closing_route_id = GetRoutingID(); | 411 params.closing_route_id = GetRoutingID(); |
404 params.new_render_process_host_id = new_render_process_host_id; | 412 params.new_render_process_host_id = new_render_process_host_id; |
405 params.new_request_id = new_request_id; | 413 params.new_request_id = new_request_id; |
406 if (IsRenderViewLive()) { | 414 if (IsRenderViewLive()) { |
407 Send(new ViewMsg_SwapOut(GetRoutingID(), params)); | 415 Send(new ViewMsg_SwapOut(GetRoutingID(), params)); |
408 } else { | 416 } else { |
409 // This RenderViewHost doesn't have a live renderer, so just skip the unload | 417 // This RenderViewHost doesn't have a live renderer, so just skip the unload |
410 // event. We must notify the ResourceDispatcherHost on the IO thread, | 418 // event. We must notify the ResourceDispatcherHost on the IO thread, |
411 // which we will do through the RenderProcessHost's widget helper. | 419 // which we will do through the RenderProcessHost's widget helper. |
412 GetProcess()->CrossSiteSwapOutACK(params); | 420 GetProcess()->SimulateSwapOutACK(params); |
413 } | 421 } |
414 } | 422 } |
415 | 423 |
416 void RenderViewHostImpl::OnSwapOutACK() { | 424 void RenderViewHostImpl::OnSwapOutACK(bool timed_out) { |
417 // Stop the hang monitor now that the unload handler has finished. | 425 // Stop the hang monitor now that the unload handler has finished. |
| 426 decrement_in_flight_event_count(); |
418 StopHangMonitorTimeout(); | 427 StopHangMonitorTimeout(); |
419 is_waiting_for_unload_ack_ = false; | 428 is_waiting_for_unload_ack_ = false; |
| 429 has_timed_out_on_unload_ = timed_out; |
420 delegate_->SwappedOut(this); | 430 delegate_->SwappedOut(this); |
421 } | 431 } |
422 | 432 |
423 void RenderViewHostImpl::WasSwappedOut() { | 433 void RenderViewHostImpl::WasSwappedOut() { |
424 // Don't bother reporting hung state anymore. | 434 // Don't bother reporting hung state anymore. |
425 StopHangMonitorTimeout(); | 435 StopHangMonitorTimeout(); |
426 | 436 |
| 437 // If we have timed out on running the unload handler, we consider |
| 438 // the process hung and we should terminate it if there are no other tabs |
| 439 // using the process. If there are other views using this process, the |
| 440 // unresponsive renderer timeout will catch it. |
| 441 bool hung = has_timed_out_on_unload_; |
| 442 |
427 // Now that we're no longer the active RVH in the tab, start filtering out | 443 // Now that we're no longer the active RVH in the tab, start filtering out |
428 // most IPC messages. Usually the renderer will have stopped sending | 444 // most IPC messages. Usually the renderer will have stopped sending |
429 // messages as of OnSwapOutACK. However, we may have timed out waiting | 445 // messages as of OnSwapOutACK. However, we may have timed out waiting |
430 // for that message, and additional IPC messages may keep streaming in. | 446 // for that message, and additional IPC messages may keep streaming in. |
431 // We filter them out, as long as that won't cause problems (e.g., we | 447 // We filter them out, as long as that won't cause problems (e.g., we |
432 // still allow synchronous messages through). | 448 // still allow synchronous messages through). |
433 SetSwappedOut(true); | 449 SetSwappedOut(true); |
434 | 450 |
| 451 // If we are not running the renderer in process and no other tab is using |
| 452 // the hung process, kill it, assuming it is a real process (unit tests don't |
| 453 // have real processes). |
| 454 if (hung) { |
| 455 base::ProcessHandle process_handle = GetProcess()->GetHandle(); |
| 456 int views = 0; |
| 457 |
| 458 // Count the number of widget hosts for the process, which is equivalent to |
| 459 // views using the process as of this writing. |
| 460 content::RenderProcessHost::RenderWidgetHostsIterator iter( |
| 461 GetProcess()->GetRenderWidgetHostsIterator()); |
| 462 for (; !iter.IsAtEnd(); iter.Advance()) |
| 463 ++views; |
| 464 |
| 465 if (!content::RenderProcessHost::run_renderer_in_process() && |
| 466 process_handle && views <= 1) { |
| 467 // We expect the delegate for this RVH to be TabContents, as it is the |
| 468 // only class that swaps out render view hosts on navigation. |
| 469 DCHECK_EQ(delegate_->GetRenderViewType(), |
| 470 content::VIEW_TYPE_TAB_CONTENTS); |
| 471 |
| 472 // Kill the process only if TabContents sets SuddenTerminationAllowed, |
| 473 // which indicates that the timer has expired. |
| 474 // This is not the case if we load data URLs or about:blank. The reason |
| 475 // is that there is no network requests and this code is hit without |
| 476 // setting the unresponsiveness timer. This allows a corner case where a |
| 477 // navigation to a data URL will leave a process running, if the |
| 478 // beforeunload handler completes fine, but the unload handler hangs. |
| 479 // At this time, the complexity to solve this edge case is not worthwhile. |
| 480 if (SuddenTerminationAllowed()) { |
| 481 base::KillProcess(process_handle, content::RESULT_CODE_HUNG, false); |
| 482 // Log a histogram point to help us diagnose how many of those kills |
| 483 // we have performed. 1 is the enum value for RendererType Normal for |
| 484 // the histogram. |
| 485 UMA_HISTOGRAM_PERCENTAGE( |
| 486 "BrowserRenderProcessHost.ChildKillsUnresponsive", 1); |
| 487 } |
| 488 } |
| 489 } |
| 490 |
435 // Inform the renderer that it can exit if no one else is using it. | 491 // Inform the renderer that it can exit if no one else is using it. |
436 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); | 492 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); |
437 } | 493 } |
438 | 494 |
439 void RenderViewHostImpl::ClosePage() { | 495 void RenderViewHostImpl::ClosePage() { |
440 // Start the hang monitor in case the renderer hangs in the unload handler. | 496 // Start the hang monitor in case the renderer hangs in the unload handler. |
441 is_waiting_for_unload_ack_ = true; | 497 is_waiting_for_unload_ack_ = true; |
442 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 498 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
443 | 499 |
444 if (IsRenderViewLive()) { | 500 if (IsRenderViewLive()) { |
| 501 // Since we are sending an IPC message to the renderer, increase the event |
| 502 // count to prevent the hang monitor timeout from being stopped by input |
| 503 // event acknowledgements. |
| 504 increment_in_flight_event_count(); |
| 505 |
445 // TODO(creis): Should this be moved to Shutdown? It may not be called for | 506 // TODO(creis): Should this be moved to Shutdown? It may not be called for |
446 // RenderViewHosts that have been swapped out. | 507 // RenderViewHosts that have been swapped out. |
447 content::NotificationService::current()->Notify( | 508 content::NotificationService::current()->Notify( |
448 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, | 509 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, |
449 content::Source<RenderViewHost>(this), | 510 content::Source<RenderViewHost>(this), |
450 content::NotificationService::NoDetails()); | 511 content::NotificationService::NoDetails()); |
451 | 512 |
452 Send(new ViewMsg_ClosePage(GetRoutingID())); | 513 Send(new ViewMsg_ClosePage(GetRoutingID())); |
453 } else { | 514 } else { |
454 // This RenderViewHost doesn't have a live renderer, so just skip the unload | 515 // This RenderViewHost doesn't have a live renderer, so just skip the unload |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
614 loop->Run(); | 675 loop->Run(); |
615 return observer.value()->DeepCopy(); | 676 return observer.value()->DeepCopy(); |
616 } | 677 } |
617 | 678 |
618 void RenderViewHostImpl::JavaScriptDialogClosed(IPC::Message* reply_msg, | 679 void RenderViewHostImpl::JavaScriptDialogClosed(IPC::Message* reply_msg, |
619 bool success, | 680 bool success, |
620 const string16& user_input) { | 681 const string16& user_input) { |
621 GetProcess()->SetIgnoreInputEvents(false); | 682 GetProcess()->SetIgnoreInputEvents(false); |
622 bool is_waiting = | 683 bool is_waiting = |
623 is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_; | 684 is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_; |
| 685 |
| 686 // If we are executing as part of (before)unload event handling, we don't |
| 687 // want to use the regular hung_renderer_delay_ms_ if the user has agreed to |
| 688 // leave the current page. In this case, use the regular timeout value used |
| 689 // during the (before)unload handling. |
624 if (is_waiting) | 690 if (is_waiting) |
625 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 691 StartHangMonitorTimeout(TimeDelta::FromMilliseconds( |
| 692 success ? kUnloadTimeoutMS : hung_renderer_delay_ms_)); |
626 | 693 |
627 ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, | 694 ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, |
628 success, user_input); | 695 success, user_input); |
629 Send(reply_msg); | 696 Send(reply_msg); |
630 | 697 |
631 // If we are waiting for an unload or beforeunload ack and the user has | 698 // If we are waiting for an unload or beforeunload ack and the user has |
632 // suppressed messages, kill the tab immediately; a page that's spamming | 699 // suppressed messages, kill the tab immediately; a page that's spamming |
633 // alerts in onbeforeunload is presumably malicious, so there's no point in | 700 // alerts in onbeforeunload is presumably malicious, so there's no point in |
634 // continuing to run its script and dragging out the process. | 701 // continuing to run its script and dragging out the process. |
635 // This must be done after sending the reply since RenderView can't close | 702 // This must be done after sending the reply since RenderView can't close |
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1303 } | 1370 } |
1304 | 1371 |
1305 void RenderViewHostImpl::OnUserGesture() { | 1372 void RenderViewHostImpl::OnUserGesture() { |
1306 delegate_->OnUserGesture(); | 1373 delegate_->OnUserGesture(); |
1307 } | 1374 } |
1308 | 1375 |
1309 void RenderViewHostImpl::OnMsgShouldCloseACK( | 1376 void RenderViewHostImpl::OnMsgShouldCloseACK( |
1310 bool proceed, | 1377 bool proceed, |
1311 const base::TimeTicks& renderer_before_unload_start_time, | 1378 const base::TimeTicks& renderer_before_unload_start_time, |
1312 const base::TimeTicks& renderer_before_unload_end_time) { | 1379 const base::TimeTicks& renderer_before_unload_end_time) { |
| 1380 decrement_in_flight_event_count(); |
1313 StopHangMonitorTimeout(); | 1381 StopHangMonitorTimeout(); |
1314 // If this renderer navigated while the beforeunload request was in flight, we | 1382 // If this renderer navigated while the beforeunload request was in flight, we |
1315 // may have cleared this state in OnMsgNavigate, in which case we can ignore | 1383 // may have cleared this state in OnMsgNavigate, in which case we can ignore |
1316 // this message. | 1384 // this message. |
1317 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) | 1385 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) |
1318 return; | 1386 return; |
1319 | 1387 |
1320 is_waiting_for_beforeunload_ack_ = false; | 1388 is_waiting_for_beforeunload_ack_ = false; |
1321 | 1389 |
1322 RenderViewHostDelegate::RendererManagement* management_delegate = | 1390 RenderViewHostDelegate::RendererManagement* management_delegate = |
(...skipping 21 matching lines...) Expand all Loading... |
1344 unload_ack_is_for_cross_site_transition_, proceed, | 1412 unload_ack_is_for_cross_site_transition_, proceed, |
1345 before_unload_end_time); | 1413 before_unload_end_time); |
1346 } | 1414 } |
1347 | 1415 |
1348 // If canceled, notify the delegate to cancel its pending navigation entry. | 1416 // If canceled, notify the delegate to cancel its pending navigation entry. |
1349 if (!proceed) | 1417 if (!proceed) |
1350 delegate_->DidCancelLoading(); | 1418 delegate_->DidCancelLoading(); |
1351 } | 1419 } |
1352 | 1420 |
1353 void RenderViewHostImpl::OnMsgClosePageACK() { | 1421 void RenderViewHostImpl::OnMsgClosePageACK() { |
| 1422 decrement_in_flight_event_count(); |
1354 ClosePageIgnoringUnloadEvents(); | 1423 ClosePageIgnoringUnloadEvents(); |
1355 } | 1424 } |
1356 | 1425 |
1357 void RenderViewHostImpl::NotifyRendererUnresponsive() { | 1426 void RenderViewHostImpl::NotifyRendererUnresponsive() { |
1358 delegate_->RendererUnresponsive( | 1427 delegate_->RendererUnresponsive( |
1359 this, is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_); | 1428 this, is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_); |
1360 } | 1429 } |
1361 | 1430 |
1362 void RenderViewHostImpl::NotifyRendererResponsive() { | 1431 void RenderViewHostImpl::NotifyRendererResponsive() { |
1363 delegate_->RendererResponsive(this); | 1432 delegate_->RendererResponsive(this); |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1719 } | 1788 } |
1720 | 1789 |
1721 void RenderViewHostImpl::SetSwappedOut(bool is_swapped_out) { | 1790 void RenderViewHostImpl::SetSwappedOut(bool is_swapped_out) { |
1722 is_swapped_out_ = is_swapped_out; | 1791 is_swapped_out_ = is_swapped_out; |
1723 | 1792 |
1724 // Whenever we change swap out state, we should not be waiting for | 1793 // Whenever we change swap out state, we should not be waiting for |
1725 // beforeunload or unload acks. We clear them here to be safe, since they | 1794 // beforeunload or unload acks. We clear them here to be safe, since they |
1726 // can cause navigations to be ignored in OnMsgNavigate. | 1795 // can cause navigations to be ignored in OnMsgNavigate. |
1727 is_waiting_for_beforeunload_ack_ = false; | 1796 is_waiting_for_beforeunload_ack_ = false; |
1728 is_waiting_for_unload_ack_ = false; | 1797 is_waiting_for_unload_ack_ = false; |
| 1798 has_timed_out_on_unload_ = false; |
1729 } | 1799 } |
1730 | 1800 |
1731 void RenderViewHostImpl::ClearPowerSaveBlockers() { | 1801 void RenderViewHostImpl::ClearPowerSaveBlockers() { |
1732 STLDeleteValues(&power_save_blockers_); | 1802 STLDeleteValues(&power_save_blockers_); |
1733 } | 1803 } |
1734 | 1804 |
1735 } // namespace content | 1805 } // namespace content |
OLD | NEW |