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 increment_in_flight_event_count(); | |
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 increment_in_flight_event_count(); | |
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 decrement_in_flight_event_count(); | |
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 widget hosts for the process, which is equivalent to | |
458 // views using the process as of this writing. | |
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_EQ(delegate_->GetRenderViewType(), | |
469 content::VIEW_TYPE_TAB_CONTENTS); | |
Charlie Reis
2012/04/10 01:19:35
nit: Align with the open paren.
nasko
2012/04/10 14:31:26
Done.
| |
470 | |
471 // Kill the process only if TabContents sets SuddenTerminationAllowed, | |
472 // which indicates that the timer has expired. | |
473 // This is not the case if we load data URLs or about:blank. The reason | |
474 // is that there is no network requests and this code is hit without | |
475 // setting the unresponsiveness timer. This allows a corner case where a | |
476 // navigation to a data URL will leave a process running, if the | |
477 // beforeunload handler completes fine, but the unload handler hangs. | |
478 // At this time, the complexity to solve this edge case is not worthwhile. | |
479 if (SuddenTerminationAllowed()) { | |
480 base::KillProcess(process_handle, content::RESULT_CODE_HUNG, false); | |
481 // Log a histogram point to help us diagnose how many of those kills | |
482 // we have performed. 1 is the enum value for RendererType Normal for | |
483 // the histogram. | |
484 UMA_HISTOGRAM_PERCENTAGE( | |
485 "BrowserRenderProcessHost.ChildKillsUnresponsive", 1); | |
486 } | |
487 } | |
488 } | |
489 | |
435 // Inform the renderer that it can exit if no one else is using it. | 490 // Inform the renderer that it can exit if no one else is using it. |
436 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); | 491 Send(new ViewMsg_WasSwappedOut(GetRoutingID())); |
437 } | 492 } |
438 | 493 |
439 void RenderViewHostImpl::ClosePage() { | 494 void RenderViewHostImpl::ClosePage() { |
440 // Start the hang monitor in case the renderer hangs in the unload handler. | 495 // Start the hang monitor in case the renderer hangs in the unload handler. |
441 is_waiting_for_unload_ack_ = true; | 496 is_waiting_for_unload_ack_ = true; |
442 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 497 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); |
443 | 498 |
444 if (IsRenderViewLive()) { | 499 if (IsRenderViewLive()) { |
500 // Since we are sending an IPC message to the renderer, increase the event | |
501 // count to prevent the hang monitor timeout from being stopped by input | |
502 // event acknowledgements. | |
503 increment_in_flight_event_count(); | |
504 | |
445 // TODO(creis): Should this be moved to Shutdown? It may not be called for | 505 // TODO(creis): Should this be moved to Shutdown? It may not be called for |
446 // RenderViewHosts that have been swapped out. | 506 // RenderViewHosts that have been swapped out. |
447 content::NotificationService::current()->Notify( | 507 content::NotificationService::current()->Notify( |
448 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, | 508 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, |
449 content::Source<RenderViewHost>(this), | 509 content::Source<RenderViewHost>(this), |
450 content::NotificationService::NoDetails()); | 510 content::NotificationService::NoDetails()); |
451 | 511 |
452 Send(new ViewMsg_ClosePage(GetRoutingID())); | 512 Send(new ViewMsg_ClosePage(GetRoutingID())); |
453 } else { | 513 } else { |
454 // This RenderViewHost doesn't have a live renderer, so just skip the unload | 514 // 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(); | 674 loop->Run(); |
615 return observer.value()->DeepCopy(); | 675 return observer.value()->DeepCopy(); |
616 } | 676 } |
617 | 677 |
618 void RenderViewHostImpl::JavaScriptDialogClosed(IPC::Message* reply_msg, | 678 void RenderViewHostImpl::JavaScriptDialogClosed(IPC::Message* reply_msg, |
619 bool success, | 679 bool success, |
620 const string16& user_input) { | 680 const string16& user_input) { |
621 GetProcess()->SetIgnoreInputEvents(false); | 681 GetProcess()->SetIgnoreInputEvents(false); |
622 bool is_waiting = | 682 bool is_waiting = |
623 is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_; | 683 is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_; |
684 | |
685 // If we are executing as part of (before)unload event handling, we don't | |
686 // want to use the regular hung_renderer_delay_ms_ if the user has agreed to | |
687 // leave the current page. In this case, use the regular timeout value used | |
688 // during the (before)unload handling. | |
624 if (is_waiting) | 689 if (is_waiting) |
625 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS)); | 690 StartHangMonitorTimeout(TimeDelta::FromMilliseconds( |
691 success ? kUnloadTimeoutMS : hung_renderer_delay_ms_)); | |
626 | 692 |
627 ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, | 693 ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, |
628 success, user_input); | 694 success, user_input); |
629 Send(reply_msg); | 695 Send(reply_msg); |
630 | 696 |
631 // If we are waiting for an unload or beforeunload ack and the user has | 697 // 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 | 698 // suppressed messages, kill the tab immediately; a page that's spamming |
633 // alerts in onbeforeunload is presumably malicious, so there's no point in | 699 // alerts in onbeforeunload is presumably malicious, so there's no point in |
634 // continuing to run its script and dragging out the process. | 700 // continuing to run its script and dragging out the process. |
635 // This must be done after sending the reply since RenderView can't close | 701 // 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 } | 1369 } |
1304 | 1370 |
1305 void RenderViewHostImpl::OnUserGesture() { | 1371 void RenderViewHostImpl::OnUserGesture() { |
1306 delegate_->OnUserGesture(); | 1372 delegate_->OnUserGesture(); |
1307 } | 1373 } |
1308 | 1374 |
1309 void RenderViewHostImpl::OnMsgShouldCloseACK( | 1375 void RenderViewHostImpl::OnMsgShouldCloseACK( |
1310 bool proceed, | 1376 bool proceed, |
1311 const base::TimeTicks& renderer_before_unload_start_time, | 1377 const base::TimeTicks& renderer_before_unload_start_time, |
1312 const base::TimeTicks& renderer_before_unload_end_time) { | 1378 const base::TimeTicks& renderer_before_unload_end_time) { |
1379 decrement_in_flight_event_count(); | |
1313 StopHangMonitorTimeout(); | 1380 StopHangMonitorTimeout(); |
1314 // If this renderer navigated while the beforeunload request was in flight, we | 1381 // 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 | 1382 // may have cleared this state in OnMsgNavigate, in which case we can ignore |
1316 // this message. | 1383 // this message. |
1317 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) | 1384 if (!is_waiting_for_beforeunload_ack_ || is_swapped_out_) |
1318 return; | 1385 return; |
1319 | 1386 |
1320 is_waiting_for_beforeunload_ack_ = false; | 1387 is_waiting_for_beforeunload_ack_ = false; |
1321 | 1388 |
1322 RenderViewHostDelegate::RendererManagement* management_delegate = | 1389 RenderViewHostDelegate::RendererManagement* management_delegate = |
(...skipping 21 matching lines...) Expand all Loading... | |
1344 unload_ack_is_for_cross_site_transition_, proceed, | 1411 unload_ack_is_for_cross_site_transition_, proceed, |
1345 before_unload_end_time); | 1412 before_unload_end_time); |
1346 } | 1413 } |
1347 | 1414 |
1348 // If canceled, notify the delegate to cancel its pending navigation entry. | 1415 // If canceled, notify the delegate to cancel its pending navigation entry. |
1349 if (!proceed) | 1416 if (!proceed) |
1350 delegate_->DidCancelLoading(); | 1417 delegate_->DidCancelLoading(); |
1351 } | 1418 } |
1352 | 1419 |
1353 void RenderViewHostImpl::OnMsgClosePageACK() { | 1420 void RenderViewHostImpl::OnMsgClosePageACK() { |
1421 decrement_in_flight_event_count(); | |
1354 ClosePageIgnoringUnloadEvents(); | 1422 ClosePageIgnoringUnloadEvents(); |
1355 } | 1423 } |
1356 | 1424 |
1357 void RenderViewHostImpl::NotifyRendererUnresponsive() { | 1425 void RenderViewHostImpl::NotifyRendererUnresponsive() { |
1358 delegate_->RendererUnresponsive( | 1426 delegate_->RendererUnresponsive( |
1359 this, is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_); | 1427 this, is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_); |
1360 } | 1428 } |
1361 | 1429 |
1362 void RenderViewHostImpl::NotifyRendererResponsive() { | 1430 void RenderViewHostImpl::NotifyRendererResponsive() { |
1363 delegate_->RendererResponsive(this); | 1431 delegate_->RendererResponsive(this); |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1719 } | 1787 } |
1720 | 1788 |
1721 void RenderViewHostImpl::SetSwappedOut(bool is_swapped_out) { | 1789 void RenderViewHostImpl::SetSwappedOut(bool is_swapped_out) { |
1722 is_swapped_out_ = is_swapped_out; | 1790 is_swapped_out_ = is_swapped_out; |
1723 | 1791 |
1724 // Whenever we change swap out state, we should not be waiting for | 1792 // 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 | 1793 // beforeunload or unload acks. We clear them here to be safe, since they |
1726 // can cause navigations to be ignored in OnMsgNavigate. | 1794 // can cause navigations to be ignored in OnMsgNavigate. |
1727 is_waiting_for_beforeunload_ack_ = false; | 1795 is_waiting_for_beforeunload_ack_ = false; |
1728 is_waiting_for_unload_ack_ = false; | 1796 is_waiting_for_unload_ack_ = false; |
1797 has_timed_out_on_unload_ = false; | |
1729 } | 1798 } |
1730 | 1799 |
1731 void RenderViewHostImpl::ClearPowerSaveBlockers() { | 1800 void RenderViewHostImpl::ClearPowerSaveBlockers() { |
1732 STLDeleteValues(&power_save_blockers_); | 1801 STLDeleteValues(&power_save_blockers_); |
1733 } | 1802 } |
1734 | 1803 |
1735 } // namespace content | 1804 } // namespace content |
OLD | NEW |