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 351 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 | 378 // (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 | 379 // 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. | 380 // both the old and the new ones are also for cross site. |
380 unload_ack_is_for_cross_site_transition_ = | 381 unload_ack_is_for_cross_site_transition_ = |
381 unload_ack_is_for_cross_site_transition_ && for_cross_site_transition; | 382 unload_ack_is_for_cross_site_transition_ && for_cross_site_transition; |
382 } else { | 383 } else { |
383 // Start the hang monitor in case the renderer hangs in the beforeunload | 384 // Start the hang monitor in case the renderer hangs in the beforeunload |
384 // handler. | 385 // handler. |
385 is_waiting_for_beforeunload_ack_ = true; | 386 is_waiting_for_beforeunload_ack_ = true; |
386 unload_ack_is_for_cross_site_transition_ = for_cross_site_transition; | 387 unload_ack_is_for_cross_site_transition_ = for_cross_site_transition; |
388 // Increment the in-flight event count, to ensure that input events won't | |
389 // cancel the timeout timer. | |
390 IncrementInFlightEventCount(); | |
387 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 391 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
388 send_should_close_start_time_ = base::TimeTicks::Now(); | 392 send_should_close_start_time_ = base::TimeTicks::Now(); |
389 Send(new ViewMsg_ShouldClose(GetRoutingID())); | 393 Send(new ViewMsg_ShouldClose(GetRoutingID())); |
390 } | 394 } |
391 } | 395 } |
392 | 396 |
393 void RenderViewHostImpl::SwapOut(int new_render_process_host_id, | 397 void RenderViewHostImpl::SwapOut(int new_render_process_host_id, |
394 int new_request_id) { | 398 int new_request_id) { |
395 // This will be set back to false in OnSwapOutACK, just before we replace | 399 // This will be set back to false in OnSwapOutACK, just before we replace |
396 // this RVH with the pending RVH. | 400 // this RVH with the pending RVH. |
397 is_waiting_for_unload_ack_ = true; | 401 is_waiting_for_unload_ack_ = true; |
398 // Start the hang monitor in case the renderer hangs in the unload handler. | 402 // Start the hang monitor in case the renderer hangs in the unload handler. |
403 // Increment the in-flight event count, to ensure that input events won't | |
404 // cancel the timeout timer. | |
405 IncrementInFlightEventCount(); | |
399 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 406 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
400 | 407 |
401 ViewMsg_SwapOut_Params params; | 408 ViewMsg_SwapOut_Params params; |
402 params.closing_process_id = GetProcess()->GetID(); | 409 params.closing_process_id = GetProcess()->GetID(); |
403 params.closing_route_id = GetRoutingID(); | 410 params.closing_route_id = GetRoutingID(); |
404 params.new_render_process_host_id = new_render_process_host_id; | 411 params.new_render_process_host_id = new_render_process_host_id; |
405 params.new_request_id = new_request_id; | 412 params.new_request_id = new_request_id; |
406 if (IsRenderViewLive()) { | 413 if (IsRenderViewLive()) { |
407 Send(new ViewMsg_SwapOut(GetRoutingID(), params)); | 414 Send(new ViewMsg_SwapOut(GetRoutingID(), params)); |
408 } else { | 415 } else { |
409 // This RenderViewHost doesn't have a live renderer, so just skip the unload | 416 // This RenderViewHost doesn't have a live renderer, so just skip the unload |
410 // event. We must notify the ResourceDispatcherHost on the IO thread, | 417 // event. We must notify the ResourceDispatcherHost on the IO thread, |
411 // which we will do through the RenderProcessHost's widget helper. | 418 // which we will do through the RenderProcessHost's widget helper. |
412 GetProcess()->CrossSiteSwapOutACK(params); | 419 GetProcess()->SimulateSwapOutACK(params); |
413 } | 420 } |
414 } | 421 } |
415 | 422 |
416 void RenderViewHostImpl::OnSwapOutACK() { | 423 void RenderViewHostImpl::OnSwapOutACK(bool timed_out) { |
417 // Stop the hang monitor now that the unload handler has finished. | 424 // Stop the hang monitor now that the unload handler has finished. |
425 DecrementInFlightEventCount(); | |
418 StopHangMonitorTimeout(); | 426 StopHangMonitorTimeout(); |
419 is_waiting_for_unload_ack_ = false; | 427 is_waiting_for_unload_ack_ = false; |
428 has_timed_out_on_unload_ = timed_out; | |
420 delegate_->SwappedOut(this); | 429 delegate_->SwappedOut(this); |
421 } | 430 } |
422 | 431 |
423 void RenderViewHostImpl::WasSwappedOut() { | 432 void RenderViewHostImpl::WasSwappedOut() { |
424 // Don't bother reporting hung state anymore. | 433 // Don't bother reporting hung state anymore. |
425 StopHangMonitorTimeout(); | 434 StopHangMonitorTimeout(); |
426 | 435 |
436 // If we have timed out on running the unload handler, we consider | |
437 // the process hung and we should terminate it if there are no other tabs | |
438 // using the process. If there are other views using this process, the | |
439 // unresponsive renderer timeout will catch it. | |
440 bool hung = has_timed_out_on_unload_; | |
441 | |
427 // Now that we're no longer the active RVH in the tab, start filtering out | 442 // 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 | 443 // most IPC messages. Usually the renderer will have stopped sending |
429 // messages as of OnSwapOutACK. However, we may have timed out waiting | 444 // messages as of OnSwapOutACK. However, we may have timed out waiting |
430 // for that message, and additional IPC messages may keep streaming in. | 445 // 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 | 446 // We filter them out, as long as that won't cause problems (e.g., we |
432 // still allow synchronous messages through). | 447 // still allow synchronous messages through). |
433 SetSwappedOut(true); | 448 SetSwappedOut(true); |
434 | 449 |
450 // If we are not running the renderer in process and no other tab is using | |
451 // the hung process, kill it, assuming it is a real process (unit tests don't | |
452 // have real processes). | |
453 if (hung) { | |
454 base::ProcessHandle process_handle = GetProcess()->GetHandle(); | |
455 int views = 0; | |
456 | |
457 // Count the number of listeners for the process, which is equivalent to | |
458 // views using the process as of this writing. | |
Charlie Reis
2012/04/06 22:34:14
We can update this comment now that the API has ch
nasko
2012/04/10 00:16:37
Done.
| |
459 content::RenderProcessHost::RenderWidgetHostsIterator iter( | |
460 GetProcess()->GetRenderWidgetHostsIterator()); | |
461 for (; !iter.IsAtEnd(); iter.Advance()) | |
462 ++views; | |
463 | |
464 if (!content::RenderProcessHost::run_renderer_in_process() && | |
465 process_handle && views <= 1) { | |
466 // We expect the delegate for this RVH to be TabContents, as it is the | |
467 // only class that swaps out render view hosts on navigation. | |
468 DCHECK(delegate_->GetRenderViewType() == content::VIEW_TYPE_TAB_CONTENTS); | |
Charlie Reis
2012/04/06 22:34:14
nit: Let's use DCHECK_EQ, which prints better erro
nasko
2012/04/10 00:16:37
Done.
| |
469 | |
470 // Kill the process only if TabContents sets SuddenTerminationAllowed, | |
471 // which indicates that the timer has expired. | |
472 // This is not the case if we load data URLs or about:blank. The reason | |
473 // is that there is no network requests and this code is hit without | |
474 // setting the unresponsiveness timer. This allows a corner case where a | |
475 // navigation to a data URL will leave a process running, if the | |
476 // beforeunload handler completes fine, but the unload handler hangs. | |
477 // At this time, the complexity to solve this edge case is not worthwhile. | |
478 if (SuddenTerminationAllowed()) { | |
479 base::KillProcess(process_handle, content::RESULT_CODE_HUNG, false); | |
480 // Log a histogram point to help us diagnose how many of those kills | |
481 // we have performed. 1 is the enum value for RendererType Normal for | |
482 // the histogram. | |
Charlie Reis
2012/04/06 22:34:14
What are the other RendererTypes? It's possible t
nasko
2012/04/10 00:16:37
No, it is an enum of Renderer and Extension. We do
Charlie Reis
2012/04/10 01:19:35
Actually, I think it would be possible to kill ext
nasko
2012/04/10 14:31:26
Considering this code is in the content module, wh
Charlie Reis
2012/04/10 17:22:04
Yeah, this doesn't matter enough to plumb it throu
| |
483 UMA_HISTOGRAM_PERCENTAGE( | |
484 "BrowserRenderProcessHost.ChildKillsUnresponsive", 1); | |
485 } | |
486 } | |
487 } | |
488 | |
435 // Inform the renderer that it can exit if no one else is using it. | 489 // Inform the renderer that it can exit if no one else is using it. |
436 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); | 490 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); |
437 } | 491 } |
438 | 492 |
439 void RenderViewHostImpl::ClosePage() { | 493 void RenderViewHostImpl::ClosePage() { |
440 // Start the hang monitor in case the renderer hangs in the unload handler. | 494 // Start the hang monitor in case the renderer hangs in the unload handler. |
441 is_waiting_for_unload_ack_ = true; | 495 is_waiting_for_unload_ack_ = true; |
442 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 496 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
Charlie Reis
2012/04/06 22:34:14
We'll need to increment the in-flight event count
nasko
2012/04/10 00:16:37
Yes. Good catch!
| |
443 | 497 |
444 if (IsRenderViewLive()) { | 498 if (IsRenderViewLive()) { |
445 // TODO(creis): Should this be moved to Shutdown? It may not be called for | 499 // TODO(creis): Should this be moved to Shutdown? It may not be called for |
446 // RenderViewHosts that have been swapped out. | 500 // RenderViewHosts that have been swapped out. |
447 content::NotificationService::current()->Notify( | 501 content::NotificationService::current()->Notify( |
448 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, | 502 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, |
449 content::Source<RenderViewHost>(this), | 503 content::Source<RenderViewHost>(this), |
450 content::NotificationService::NoDetails()); | 504 content::NotificationService::NoDetails()); |
451 | 505 |
452 Send(new ViewMsg_ClosePage(GetRoutingID())); | 506 Send(new ViewMsg_ClosePage(GetRoutingID())); |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
615 return observer.value()->DeepCopy(); | 669 return observer.value()->DeepCopy(); |
616 } | 670 } |
617 | 671 |
618 void RenderViewHostImpl::JavaScriptDialogClosed(IPC::Message* reply_msg, | 672 void RenderViewHostImpl::JavaScriptDialogClosed(IPC::Message* reply_msg, |
619 bool success, | 673 bool success, |
620 const string16& user_input) { | 674 const string16& user_input) { |
621 GetProcess()->SetIgnoreInputEvents(false); | 675 GetProcess()->SetIgnoreInputEvents(false); |
622 bool is_waiting = | 676 bool is_waiting = |
623 is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_; | 677 is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_; |
624 if (is_waiting) | 678 if (is_waiting) |
625 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 679 StartHangMonitorTimeout(TimeDelta::FromMilliseconds( |
680 success ? kUnloadTimeoutMS : hung_renderer_delay_ms_)); | |
Charlie Reis
2012/04/06 22:34:14
A comment explaining why we use the short vs the l
nasko
2012/04/10 00:16:37
Yes, we are still expecting the ACK, but the count
| |
626 | 681 |
627 ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, | 682 ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, |
628 success, user_input); | 683 success, user_input); |
629 Send(reply_msg); | 684 Send(reply_msg); |
630 | 685 |
631 // If we are waiting for an unload or beforeunload ack and the user has | 686 // 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 | 687 // suppressed messages, kill the tab immediately; a page that's spamming |
633 // alerts in onbeforeunload is presumably malicious, so there's no point in | 688 // alerts in onbeforeunload is presumably malicious, so there's no point in |
634 // continuing to run its script and dragging out the process. | 689 // continuing to run its script and dragging out the process. |
635 // This must be done after sending the reply since RenderView can't close | 690 // 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 } | 1358 } |
1304 | 1359 |
1305 void RenderViewHostImpl::OnUserGesture() { | 1360 void RenderViewHostImpl::OnUserGesture() { |
1306 delegate_->OnUserGesture(); | 1361 delegate_->OnUserGesture(); |
1307 } | 1362 } |
1308 | 1363 |
1309 void RenderViewHostImpl::OnMsgShouldCloseACK( | 1364 void RenderViewHostImpl::OnMsgShouldCloseACK( |
1310 bool proceed, | 1365 bool proceed, |
1311 const base::TimeTicks& renderer_before_unload_start_time, | 1366 const base::TimeTicks& renderer_before_unload_start_time, |
1312 const base::TimeTicks& renderer_before_unload_end_time) { | 1367 const base::TimeTicks& renderer_before_unload_end_time) { |
1368 DecrementInFlightEventCount(); | |
1313 StopHangMonitorTimeout(); | 1369 StopHangMonitorTimeout(); |
1314 // If this renderer navigated while the beforeunload request was in flight, we | 1370 // 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 | 1371 // may have cleared this state in OnMsgNavigate, in which case we can ignore |
1316 // this message. | 1372 // this message. |
1317 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) | 1373 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) |
1318 return; | 1374 return; |
1319 | 1375 |
1320 is_waiting_for_beforeunload_ack_ = false; | 1376 is_waiting_for_beforeunload_ack_ = false; |
1321 | 1377 |
1322 RenderViewHostDelegate::RendererManagement* management_delegate = | 1378 RenderViewHostDelegate::RendererManagement* management_delegate = |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1719 } | 1775 } |
1720 | 1776 |
1721 void RenderViewHostImpl::SetSwappedOut(bool is_swapped_out) { | 1777 void RenderViewHostImpl::SetSwappedOut(bool is_swapped_out) { |
1722 is_swapped_out_ = is_swapped_out; | 1778 is_swapped_out_ = is_swapped_out; |
1723 | 1779 |
1724 // Whenever we change swap out state, we should not be waiting for | 1780 // 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 | 1781 // beforeunload or unload acks. We clear them here to be safe, since they |
1726 // can cause navigations to be ignored in OnMsgNavigate. | 1782 // can cause navigations to be ignored in OnMsgNavigate. |
1727 is_waiting_for_beforeunload_ack_ = false; | 1783 is_waiting_for_beforeunload_ack_ = false; |
1728 is_waiting_for_unload_ack_ = false; | 1784 is_waiting_for_unload_ack_ = false; |
1785 | |
Charlie Reis
2012/04/06 22:34:14
nit: No whitespace needed here. This falls in the
nasko
2012/04/10 00:16:37
Done.
| |
1786 has_timed_out_on_unload_ = false; | |
1729 } | 1787 } |
1730 | 1788 |
1731 void RenderViewHostImpl::ClearPowerSaveBlockers() { | 1789 void RenderViewHostImpl::ClearPowerSaveBlockers() { |
1732 STLDeleteValues(&power_save_blockers_); | 1790 STLDeleteValues(&power_save_blockers_); |
1733 } | 1791 } |
1734 | 1792 |
1735 } // namespace content | 1793 } // namespace content |
OLD | NEW |