Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/frame_host/render_frame_host_impl.h" | 5 #include "content/browser/frame_host/render_frame_host_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/containers/hash_tables.h" | 9 #include "base/containers/hash_tables.h" |
| 10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| (...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 | 700 |
| 701 // If we're waiting for a cross-site beforeunload ack from this renderer and | 701 // If we're waiting for a cross-site beforeunload ack from this renderer and |
| 702 // we receive a Navigate message from the main frame, then the renderer was | 702 // we receive a Navigate message from the main frame, then the renderer was |
| 703 // navigating already and sent it before hearing the FrameMsg_Stop message. | 703 // navigating already and sent it before hearing the FrameMsg_Stop message. |
| 704 // We do not want to cancel the pending navigation in this case, since the | 704 // We do not want to cancel the pending navigation in this case, since the |
| 705 // old page will soon be stopped. Instead, treat this as a beforeunload ack | 705 // old page will soon be stopped. Instead, treat this as a beforeunload ack |
| 706 // to allow the pending navigation to continue. | 706 // to allow the pending navigation to continue. |
| 707 if (is_waiting_for_beforeunload_ack_ && | 707 if (is_waiting_for_beforeunload_ack_ && |
| 708 unload_ack_is_for_cross_site_transition_ && | 708 unload_ack_is_for_cross_site_transition_ && |
| 709 ui::PageTransitionIsMainFrame(validated_params.transition)) { | 709 ui::PageTransitionIsMainFrame(validated_params.transition)) { |
| 710 OnBeforeUnloadACK(true, send_before_unload_start_time_, | 710 base::TimeTicks approx_renderer_start_time = send_before_unload_start_time_; |
|
carlosk
2014/10/21 13:07:09
I'm making this copy because it was unsafe to pass
Charlie Reis
2014/10/21 18:21:48
"Could be reset anytime" doesn't seem relevant her
carlosk
2014/10/22 09:08:56
Yeah I agree with that: it isn't really required.
| |
| 711 base::TimeTicks::Now()); | 711 OnBeforeUnloadACK(true, approx_renderer_start_time, base::TimeTicks::Now()); |
| 712 return; | 712 return; |
| 713 } | 713 } |
| 714 | 714 |
| 715 // If we're waiting for an unload ack from this renderer and we receive a | 715 // If we're waiting for an unload ack from this renderer and we receive a |
| 716 // Navigate message, then the renderer was navigating before it received the | 716 // Navigate message, then the renderer was navigating before it received the |
| 717 // unload request. It will either respond to the unload request soon or our | 717 // unload request. It will either respond to the unload request soon or our |
| 718 // timer will expire. Either way, we should ignore this message, because we | 718 // timer will expire. Either way, we should ignore this message, because we |
| 719 // have already committed to closing this renderer. | 719 // have already committed to closing this renderer. |
| 720 if (IsWaitingForUnloadACK()) | 720 if (IsWaitingForUnloadACK()) |
| 721 return; | 721 return; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 823 if (!GetParent()) | 823 if (!GetParent()) |
| 824 delegate_->SwappedOut(this); | 824 delegate_->SwappedOut(this); |
| 825 } | 825 } |
| 826 | 826 |
| 827 void RenderFrameHostImpl::OnBeforeUnloadACK( | 827 void RenderFrameHostImpl::OnBeforeUnloadACK( |
| 828 bool proceed, | 828 bool proceed, |
| 829 const base::TimeTicks& renderer_before_unload_start_time, | 829 const base::TimeTicks& renderer_before_unload_start_time, |
| 830 const base::TimeTicks& renderer_before_unload_end_time) { | 830 const base::TimeTicks& renderer_before_unload_end_time) { |
| 831 TRACE_EVENT_ASYNC_END0( | 831 TRACE_EVENT_ASYNC_END0( |
| 832 "navigation", "RenderFrameHostImpl::BeforeUnload", this); | 832 "navigation", "RenderFrameHostImpl::BeforeUnload", this); |
| 833 // TODO(creis): Support beforeunload on subframes. For now just pretend that | 833 DCHECK(!GetParent()); |
| 834 // the handler ran and allowed the navigation to proceed. | |
| 835 if (GetParent()) { | |
| 836 is_waiting_for_beforeunload_ack_ = false; | |
| 837 frame_tree_node_->render_manager()->OnBeforeUnloadACK( | |
| 838 unload_ack_is_for_cross_site_transition_, proceed, | |
| 839 renderer_before_unload_end_time); | |
| 840 return; | |
| 841 } | |
| 842 | |
| 843 render_view_host_->decrement_in_flight_event_count(); | 834 render_view_host_->decrement_in_flight_event_count(); |
| 844 render_view_host_->StopHangMonitorTimeout(); | 835 render_view_host_->StopHangMonitorTimeout(); |
| 845 // If this renderer navigated while the beforeunload request was in flight, we | 836 // If this renderer navigated while the beforeunload request was in flight, we |
| 846 // may have cleared this state in OnDidCommitProvisionalLoad, in which case we | 837 // may have cleared this state in OnDidCommitProvisionalLoad, in which case we |
| 847 // can ignore this message. | 838 // can ignore this message. |
| 848 // However renderer might also be swapped out but we still want to proceed | 839 // However renderer might also be swapped out but we still want to proceed |
| 849 // with navigation, otherwise it would block future navigations. This can | 840 // with navigation, otherwise it would block future navigations. This can |
| 850 // happen when pending cross-site navigation is canceled by a second one just | 841 // happen when pending cross-site navigation is canceled by a second one just |
| 851 // before OnDidCommitProvisionalLoad while current RVH is waiting for commit | 842 // before OnDidCommitProvisionalLoad while current RVH is waiting for commit |
| 852 // but second navigation is started from the beginning. | 843 // but second navigation is started from the beginning. |
| 853 if (!is_waiting_for_beforeunload_ack_) { | 844 if (!is_waiting_for_beforeunload_ack_) { |
| 854 return; | 845 return; |
| 855 } | 846 } |
| 847 DCHECK(!send_before_unload_start_time_.is_null()); | |
| 856 | 848 |
| 857 is_waiting_for_beforeunload_ack_ = false; | 849 // Sets a default value for before_unload_end_time so that the browser |
| 858 | 850 // survives a hacked renderer. |
| 859 base::TimeTicks before_unload_end_time; | 851 base::TimeTicks before_unload_end_time = renderer_before_unload_end_time; |
|
carlosk
2014/10/21 13:07:09
So finally, this initialization was not the correc
| |
| 860 if (!send_before_unload_start_time_.is_null() && | 852 if (!renderer_before_unload_start_time.is_null() && |
| 861 !renderer_before_unload_start_time.is_null() && | |
| 862 !renderer_before_unload_end_time.is_null()) { | 853 !renderer_before_unload_end_time.is_null()) { |
| 863 // When passing TimeTicks across process boundaries, we need to compensate | 854 // When passing TimeTicks across process boundaries, we need to compensate |
| 864 // for any skew between the processes. Here we are converting the | 855 // for any skew between the processes. Here we are converting the |
| 865 // renderer's notion of before_unload_end_time to TimeTicks in the browser | 856 // renderer's notion of before_unload_end_time to TimeTicks in the browser |
| 866 // process. See comments in inter_process_time_ticks_converter.h for more. | 857 // process. See comments in inter_process_time_ticks_converter.h for more. |
| 858 base::TimeTicks receive_before_unload_ack_time = base::TimeTicks::Now(); | |
| 867 InterProcessTimeTicksConverter converter( | 859 InterProcessTimeTicksConverter converter( |
| 868 LocalTimeTicks::FromTimeTicks(send_before_unload_start_time_), | 860 LocalTimeTicks::FromTimeTicks(send_before_unload_start_time_), |
| 869 LocalTimeTicks::FromTimeTicks(base::TimeTicks::Now()), | 861 LocalTimeTicks::FromTimeTicks(receive_before_unload_ack_time), |
| 870 RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time), | 862 RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time), |
| 871 RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time)); | 863 RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time)); |
| 872 LocalTimeTicks browser_before_unload_end_time = | 864 LocalTimeTicks browser_before_unload_end_time = |
| 873 converter.ToLocalTimeTicks( | 865 converter.ToLocalTimeTicks( |
| 874 RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time)); | 866 RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time)); |
| 875 before_unload_end_time = browser_before_unload_end_time.ToTimeTicks(); | 867 before_unload_end_time = browser_before_unload_end_time.ToTimeTicks(); |
| 876 | 868 |
| 877 // Collect UMA on the inter-process skew. | 869 // Collect UMA on the inter-process skew. |
| 878 bool is_skew_additive = false; | 870 bool is_skew_additive = false; |
| 879 if (converter.IsSkewAdditiveForMetrics()) { | 871 if (converter.IsSkewAdditiveForMetrics()) { |
| 880 is_skew_additive = true; | 872 is_skew_additive = true; |
| 881 base::TimeDelta skew = converter.GetSkewForMetrics(); | 873 base::TimeDelta skew = converter.GetSkewForMetrics(); |
| 882 if (skew >= base::TimeDelta()) { | 874 if (skew >= base::TimeDelta()) { |
| 883 UMA_HISTOGRAM_TIMES( | 875 UMA_HISTOGRAM_TIMES( |
| 884 "InterProcessTimeTicks.BrowserBehind_RendererToBrowser", skew); | 876 "InterProcessTimeTicks.BrowserBehind_RendererToBrowser", skew); |
| 885 } else { | 877 } else { |
| 886 UMA_HISTOGRAM_TIMES( | 878 UMA_HISTOGRAM_TIMES( |
| 887 "InterProcessTimeTicks.BrowserAhead_RendererToBrowser", -skew); | 879 "InterProcessTimeTicks.BrowserAhead_RendererToBrowser", -skew); |
| 888 } | 880 } |
| 889 } | 881 } |
| 890 UMA_HISTOGRAM_BOOLEAN( | 882 UMA_HISTOGRAM_BOOLEAN( |
| 891 "InterProcessTimeTicks.IsSkewAdditive_RendererToBrowser", | 883 "InterProcessTimeTicks.IsSkewAdditive_RendererToBrowser", |
| 892 is_skew_additive); | 884 is_skew_additive); |
| 893 | 885 |
| 886 base::TimeDelta on_before_unload_overhead_time = | |
| 887 (receive_before_unload_ack_time - send_before_unload_start_time_) - | |
| 888 (renderer_before_unload_end_time - renderer_before_unload_start_time); | |
| 889 UMA_HISTOGRAM_TIMES("Navigation.OnBeforeUnloadOverheadTime", | |
| 890 on_before_unload_overhead_time); | |
| 891 | |
| 894 frame_tree_node_->navigator()->LogBeforeUnloadTime( | 892 frame_tree_node_->navigator()->LogBeforeUnloadTime( |
| 895 renderer_before_unload_start_time, renderer_before_unload_end_time); | 893 renderer_before_unload_start_time, renderer_before_unload_end_time); |
| 896 } | 894 } |
| 895 // Resets beforeunload waiting state. | |
|
Charlie Reis
2014/10/21 18:21:48
nit: There should have been a blank line before th
carlosk
2014/10/22 09:08:56
Acknowledged.
| |
| 896 is_waiting_for_beforeunload_ack_ = false; | |
| 897 send_before_unload_start_time_ = base::TimeTicks(); | |
|
carlosk
2014/10/21 13:07:09
I moved the state reset down here so that both var
Charlie Reis
2014/10/21 18:21:48
Acknowledged.
| |
| 898 | |
| 897 frame_tree_node_->render_manager()->OnBeforeUnloadACK( | 899 frame_tree_node_->render_manager()->OnBeforeUnloadACK( |
| 898 unload_ack_is_for_cross_site_transition_, proceed, | 900 unload_ack_is_for_cross_site_transition_, proceed, |
| 899 before_unload_end_time); | 901 before_unload_end_time); |
| 900 | 902 |
| 901 // If canceled, notify the delegate to cancel its pending navigation entry. | 903 // If canceled, notify the delegate to cancel its pending navigation entry. |
| 902 if (!proceed) | 904 if (!proceed) |
| 903 render_view_host_->GetDelegate()->DidCancelLoading(); | 905 render_view_host_->GetDelegate()->DidCancelLoading(); |
| 904 } | 906 } |
| 905 | 907 |
| 906 bool RenderFrameHostImpl::IsWaitingForUnloadACK() const { | 908 bool RenderFrameHostImpl::IsWaitingForUnloadACK() const { |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1217 // Whenever we change the RFH state to and from active or swapped out state, | 1219 // Whenever we change the RFH state to and from active or swapped out state, |
| 1218 // we should not be waiting for beforeunload or close acks. We clear them | 1220 // we should not be waiting for beforeunload or close acks. We clear them |
| 1219 // here to be safe, since they can cause navigations to be ignored in | 1221 // here to be safe, since they can cause navigations to be ignored in |
| 1220 // OnDidCommitProvisionalLoad. | 1222 // OnDidCommitProvisionalLoad. |
| 1221 // TODO(creis): Move is_waiting_for_beforeunload_ack_ into the state machine. | 1223 // TODO(creis): Move is_waiting_for_beforeunload_ack_ into the state machine. |
| 1222 if (rfh_state == STATE_DEFAULT || | 1224 if (rfh_state == STATE_DEFAULT || |
| 1223 rfh_state == STATE_SWAPPED_OUT || | 1225 rfh_state == STATE_SWAPPED_OUT || |
| 1224 rfh_state_ == STATE_DEFAULT || | 1226 rfh_state_ == STATE_DEFAULT || |
| 1225 rfh_state_ == STATE_SWAPPED_OUT) { | 1227 rfh_state_ == STATE_SWAPPED_OUT) { |
| 1226 is_waiting_for_beforeunload_ack_ = false; | 1228 is_waiting_for_beforeunload_ack_ = false; |
| 1229 send_before_unload_start_time_ = base::TimeTicks(); | |
| 1227 render_view_host_->is_waiting_for_close_ack_ = false; | 1230 render_view_host_->is_waiting_for_close_ack_ = false; |
| 1228 } | 1231 } |
| 1229 rfh_state_ = rfh_state; | 1232 rfh_state_ = rfh_state; |
| 1230 } | 1233 } |
| 1231 | 1234 |
| 1232 bool RenderFrameHostImpl::CanCommitURL(const GURL& url) { | 1235 bool RenderFrameHostImpl::CanCommitURL(const GURL& url) { |
| 1233 // TODO(creis): We should also check for WebUI pages here. Also, when the | 1236 // TODO(creis): We should also check for WebUI pages here. Also, when the |
| 1234 // out-of-process iframes implementation is ready, we should check for | 1237 // out-of-process iframes implementation is ready, we should check for |
| 1235 // cross-site URLs that are not allowed to commit in this process. | 1238 // cross-site URLs that are not allowed to commit in this process. |
| 1236 | 1239 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1301 | 1304 |
| 1302 void RenderFrameHostImpl::OpenURL(const FrameHostMsg_OpenURL_Params& params) { | 1305 void RenderFrameHostImpl::OpenURL(const FrameHostMsg_OpenURL_Params& params) { |
| 1303 OnOpenURL(params); | 1306 OnOpenURL(params); |
| 1304 } | 1307 } |
| 1305 | 1308 |
| 1306 void RenderFrameHostImpl::Stop() { | 1309 void RenderFrameHostImpl::Stop() { |
| 1307 Send(new FrameMsg_Stop(routing_id_)); | 1310 Send(new FrameMsg_Stop(routing_id_)); |
| 1308 } | 1311 } |
| 1309 | 1312 |
| 1310 void RenderFrameHostImpl::DispatchBeforeUnload(bool for_cross_site_transition) { | 1313 void RenderFrameHostImpl::DispatchBeforeUnload(bool for_cross_site_transition) { |
| 1314 // TODO(creis): Support beforeunload on subframes. For now just pretend that | |
| 1315 // the handler ran and allowed the navigation to proceed. | |
| 1316 if (GetParent() || !IsRenderFrameLive()) { | |
| 1317 // We don't have a live renderer, so just skip running beforeunload. | |
| 1318 frame_tree_node_->render_manager()->OnBeforeUnloadACK( | |
| 1319 for_cross_site_transition, true, base::TimeTicks::Now()); | |
| 1320 return; | |
| 1321 } | |
| 1311 TRACE_EVENT_ASYNC_BEGIN0( | 1322 TRACE_EVENT_ASYNC_BEGIN0( |
| 1312 "navigation", "RenderFrameHostImpl::BeforeUnload", this); | 1323 "navigation", "RenderFrameHostImpl::BeforeUnload", this); |
| 1313 // TODO(creis): Support subframes. | |
| 1314 if (GetParent() || !IsRenderFrameLive()) { | |
| 1315 // We don't have a live renderer, so just skip running beforeunload. | |
| 1316 is_waiting_for_beforeunload_ack_ = true; | |
| 1317 unload_ack_is_for_cross_site_transition_ = for_cross_site_transition; | |
| 1318 base::TimeTicks now = base::TimeTicks::Now(); | |
| 1319 OnBeforeUnloadACK(true, now, now); | |
| 1320 return; | |
| 1321 } | |
| 1322 | 1324 |
| 1323 // This may be called more than once (if the user clicks the tab close button | 1325 // This may be called more than once (if the user clicks the tab close button |
| 1324 // several times, or if she clicks the tab close button then the browser close | 1326 // several times, or if she clicks the tab close button then the browser close |
| 1325 // button), and we only send the message once. | 1327 // button), and we only send the message once. |
| 1326 if (is_waiting_for_beforeunload_ack_) { | 1328 if (is_waiting_for_beforeunload_ack_) { |
| 1327 // Some of our close messages could be for the tab, others for cross-site | 1329 // Some of our close messages could be for the tab, others for cross-site |
| 1328 // transitions. We always want to think it's for closing the tab if any | 1330 // transitions. We always want to think it's for closing the tab if any |
| 1329 // of the messages were, since otherwise it might be impossible to close | 1331 // of the messages were, since otherwise it might be impossible to close |
| 1330 // (if there was a cross-site "close" request pending when the user clicked | 1332 // (if there was a cross-site "close" request pending when the user clicked |
| 1331 // the close button). We want to keep the "for cross site" flag only if | 1333 // the close button). We want to keep the "for cross site" flag only if |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1562 // Clear any state if a pending navigation is canceled or preempted. | 1564 // Clear any state if a pending navigation is canceled or preempted. |
| 1563 if (suspended_nav_params_) | 1565 if (suspended_nav_params_) |
| 1564 suspended_nav_params_.reset(); | 1566 suspended_nav_params_.reset(); |
| 1565 | 1567 |
| 1566 TRACE_EVENT_ASYNC_END0("navigation", | 1568 TRACE_EVENT_ASYNC_END0("navigation", |
| 1567 "RenderFrameHostImpl navigation suspended", this); | 1569 "RenderFrameHostImpl navigation suspended", this); |
| 1568 navigations_suspended_ = false; | 1570 navigations_suspended_ = false; |
| 1569 } | 1571 } |
| 1570 | 1572 |
| 1571 } // namespace content | 1573 } // namespace content |
| OLD | NEW |