1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h"
6
7 #include "components/page_load_metrics/browser/page_load_metrics_util.h"
8
9 using page_load_metrics::PageAbortReason;
10
11 namespace internal {
12
13 const char kHistogramAbortForwardBackBeforeCommit[] =
14 "PageLoad.Experimental.AbortTiming.ForwardBackNavigation.BeforeCommit";
15 const char kHistogramAbortReloadBeforeCommit[] =
16 "PageLoad.Experimental.AbortTiming.Reload.BeforeCommit";
17 const char kHistogramAbortNewNavigationBeforeCommit[] =
18 "PageLoad.Experimental.AbortTiming.NewNavigation.BeforeCommit";
19 const char kHistogramAbortStopBeforeCommit[] =
20 "PageLoad.Experimental.AbortTiming.Stop.BeforeCommit";
21 const char kHistogramAbortCloseBeforeCommit[] =
22 "PageLoad.Experimental.AbortTiming.Close.BeforeCommit";
23 const char kHistogramAbortBackgroundBeforeCommit[] =
24 "PageLoad.Experimental.AbortTiming.Background.BeforeCommit";
25 const char kHistogramAbortOtherBeforeCommit[] =
26 "PageLoad.Experimental.AbortTiming.Other.BeforeCommit";
27
28 const char kHistogramAbortForwardBackBeforePaint[] =
29 "PageLoad.Experimental.AbortTiming.ForwardBackNavigation.AfterCommit."
30 "BeforePaint";
31 const char kHistogramAbortReloadBeforePaint[] =
32 "PageLoad.Experimental.AbortTiming.Reload.AfterCommit.BeforePaint";
33 const char kHistogramAbortNewNavigationBeforePaint[] =
34 "PageLoad.Experimental.AbortTiming.NewNavigation.AfterCommit.BeforePaint";
35 const char kHistogramAbortStopBeforePaint[] =
36 "PageLoad.Experimental.AbortTiming.Stop.AfterCommit.BeforePaint";
37 const char kHistogramAbortCloseBeforePaint[] =
38 "PageLoad.Experimental.AbortTiming.Close.AfterCommit.BeforePaint";
39 const char kHistogramAbortBackgroundBeforePaint[] =
40 "PageLoad.Experimental.AbortTiming.Background.AfterCommit.BeforePaint";
41
42 const char kHistogramAbortForwardBackDuringParse[] =
43 "PageLoad.Experimental.AbortTiming.ForwardBackNavigation.DuringParse";
44 const char kHistogramAbortReloadDuringParse[] =
45 "PageLoad.Experimental.AbortTiming.Reload.DuringParse";
46 const char kHistogramAbortNewNavigationDuringParse[] =
47 "PageLoad.Experimental.AbortTiming.NewNavigation.DuringParse";
48 const char kHistogramAbortStopDuringParse[] =
49 "PageLoad.Experimental.AbortTiming.Stop.DuringParse";
50 const char kHistogramAbortCloseDuringParse[] =
51 "PageLoad.Experimental.AbortTiming.Close.DuringParse";
52 const char kHistogramAbortBackgroundDuringParse[] =
53 "PageLoad.Experimental.AbortTiming.Background.DuringParse";
54
55 } // namespace internal
56
57 namespace {
58
RecordAbortBeforeCommit(const page_load_metrics::PageAbortInfo & abort_info)59 void RecordAbortBeforeCommit(
60 const page_load_metrics::PageAbortInfo& abort_info) {
61 switch (abort_info.reason) {
62 case PageAbortReason::ABORT_RELOAD:
63 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadBeforeCommit,
64 abort_info.time_to_abort);
65 if (abort_info.user_initiated_info.user_gesture) {
66 PAGE_LOAD_HISTOGRAM(
67 "PageLoad.Experimental.AbortTiming.Reload.BeforeCommit."
68 "UserGesture",
69 abort_info.time_to_abort);
70 }
71 if (abort_info.user_initiated_info.browser_initiated) {
72 PAGE_LOAD_HISTOGRAM(
73 "PageLoad.Experimental.AbortTiming.Reload.BeforeCommit."
74 "BrowserInitiated",
75 abort_info.time_to_abort);
76 }
77 return;
78 case PageAbortReason::ABORT_FORWARD_BACK:
79 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforeCommit,
80 abort_info.time_to_abort);
81 if (abort_info.user_initiated_info.user_gesture) {
82 PAGE_LOAD_HISTOGRAM(
83 "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
84 "BeforeCommit.UserGesture",
85 abort_info.time_to_abort);
86 }
87 if (abort_info.user_initiated_info.browser_initiated) {
88 PAGE_LOAD_HISTOGRAM(
89 "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
90 "BeforeCommit.BrowserInitiated",
91 abort_info.time_to_abort);
92 }
93 return;
94 case PageAbortReason::ABORT_NEW_NAVIGATION:
95 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforeCommit,
96 abort_info.time_to_abort);
97 if (abort_info.user_initiated_info.user_gesture) {
98 PAGE_LOAD_HISTOGRAM(
99 "PageLoad.Experimental.AbortTiming.NewNavigation.BeforeCommit."
100 "UserGesture",
101 abort_info.time_to_abort);
102 }
103 if (abort_info.user_initiated_info.browser_initiated) {
104 PAGE_LOAD_HISTOGRAM(
105 "PageLoad.Experimental.AbortTiming.NewNavigation.BeforeCommit."
106 "BrowserInitiated",
107 abort_info.time_to_abort);
108 }
109 return;
110 case PageAbortReason::ABORT_STOP:
111 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopBeforeCommit,
112 abort_info.time_to_abort);
113 return;
114 case PageAbortReason::ABORT_CLOSE:
115 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseBeforeCommit,
116 abort_info.time_to_abort);
117 return;
118 case PageAbortReason::ABORT_BACKGROUND:
119 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortBackgroundBeforeCommit,
120 abort_info.time_to_abort);
121 return;
122 case PageAbortReason::ABORT_OTHER:
123 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortOtherBeforeCommit,
124 abort_info.time_to_abort);
125 return;
126 case PageAbortReason::ABORT_NONE:
127 NOTREACHED();
128 return;
129 }
130 NOTREACHED();
131 }
132
RecordAbortAfterCommitBeforePaint(const page_load_metrics::PageAbortInfo & abort_info)133 void RecordAbortAfterCommitBeforePaint(
134 const page_load_metrics::PageAbortInfo& abort_info) {
135 switch (abort_info.reason) {
136 case PageAbortReason::ABORT_RELOAD:
137 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadBeforePaint,
138 abort_info.time_to_abort);
139 if (abort_info.user_initiated_info.user_gesture) {
140 PAGE_LOAD_HISTOGRAM(
141 "PageLoad.Experimental.AbortTiming.Reload.AfterCommit.BeforePaint."
142 "UserGesture",
143 abort_info.time_to_abort);
144 }
145 if (abort_info.user_initiated_info.browser_initiated) {
146 PAGE_LOAD_HISTOGRAM(
147 "PageLoad.Experimental.AbortTiming.Reload.AfterCommit.BeforePaint."
148 "BrowserInitiated",
149 abort_info.time_to_abort);
150 }
151 return;
152 case PageAbortReason::ABORT_FORWARD_BACK:
153 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforePaint,
154 abort_info.time_to_abort);
155 if (abort_info.user_initiated_info.user_gesture) {
156 PAGE_LOAD_HISTOGRAM(
157 "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
158 "AfterCommit.BeforePaint.UserGesture",
159 abort_info.time_to_abort);
160 }
161 if (abort_info.user_initiated_info.browser_initiated) {
162 PAGE_LOAD_HISTOGRAM(
163 "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
164 "AfterCommit.BeforePaint.BrowserInitiated",
165 abort_info.time_to_abort);
166 }
167 return;
168 case PageAbortReason::ABORT_NEW_NAVIGATION:
169 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforePaint,
170 abort_info.time_to_abort);
171 if (abort_info.user_initiated_info.user_gesture) {
172 PAGE_LOAD_HISTOGRAM(
173 "PageLoad.Experimental.AbortTiming.NewNavigation.AfterCommit."
174 "BeforePaint.UserGesture",
175 abort_info.time_to_abort);
176 }
177 if (abort_info.user_initiated_info.browser_initiated) {
178 PAGE_LOAD_HISTOGRAM(
179 "PageLoad.Experimental.AbortTiming.NewNavigation.AfterCommit."
180 "BeforePaint.BrowserInitiated",
181 abort_info.time_to_abort);
182 }
183 return;
184 case PageAbortReason::ABORT_STOP:
185 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopBeforePaint,
186 abort_info.time_to_abort);
187 return;
188 case PageAbortReason::ABORT_CLOSE:
189 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseBeforePaint,
190 abort_info.time_to_abort);
191 return;
192 case PageAbortReason::ABORT_BACKGROUND:
193 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortBackgroundBeforePaint,
194 abort_info.time_to_abort);
195 return;
196 case PageAbortReason::ABORT_OTHER:
197 // This is technically possible, though rare. See ~PageLoadTracker for an
198 // explanation.
199 return;
200 case PageAbortReason::ABORT_NONE:
201 NOTREACHED();
202 return;
203 }
204 NOTREACHED();
205 }
206
RecordAbortDuringParse(const page_load_metrics::PageAbortInfo & abort_info)207 void RecordAbortDuringParse(
208 const page_load_metrics::PageAbortInfo& abort_info) {
209 switch (abort_info.reason) {
210 case PageAbortReason::ABORT_RELOAD:
211 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadDuringParse,
212 abort_info.time_to_abort);
213 return;
214 case PageAbortReason::ABORT_FORWARD_BACK:
215 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackDuringParse,
216 abort_info.time_to_abort);
217 return;
218 case PageAbortReason::ABORT_NEW_NAVIGATION:
219 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationDuringParse,
220 abort_info.time_to_abort);
221 return;
222 case PageAbortReason::ABORT_STOP:
223 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopDuringParse,
224 abort_info.time_to_abort);
225 return;
226 case PageAbortReason::ABORT_CLOSE:
227 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseDuringParse,
228 abort_info.time_to_abort);
229 return;
230 case PageAbortReason::ABORT_BACKGROUND:
231 PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortBackgroundDuringParse,
232 abort_info.time_to_abort);
233 return;
234 case PageAbortReason::ABORT_OTHER:
235 // This is technically possible, though rare. See ~PageLoadTracker for an
236 // explanation.
237 return;
238 case PageAbortReason::ABORT_NONE:
239 NOTREACHED();
240 return;
241 }
242 NOTREACHED();
243 }
244
ShouldTrackMetrics(const page_load_metrics::PageLoadMetricsObserverDelegate & delegate,const page_load_metrics::PageAbortInfo & abort_info)245 bool ShouldTrackMetrics(
246 const page_load_metrics::PageLoadMetricsObserverDelegate& delegate,
247 const page_load_metrics::PageAbortInfo& abort_info) {
248 if (abort_info.reason == PageAbortReason::ABORT_NONE)
249 return false;
250
251 // Don't log abort times if the page was backgrounded before the abort event.
252 if (!page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
253 abort_info.time_to_abort, delegate))
254 return false;
255
256 return true;
257 }
258
259 } // namespace
260
AbortsPageLoadMetricsObserver()261 AbortsPageLoadMetricsObserver::AbortsPageLoadMetricsObserver() {}
262
OnComplete(const page_load_metrics::mojom::PageLoadTiming & timing)263 void AbortsPageLoadMetricsObserver::OnComplete(
264 const page_load_metrics::mojom::PageLoadTiming& timing) {
265 page_load_metrics::PageAbortInfo abort_info = GetPageAbortInfo(GetDelegate());
266 if (!ShouldTrackMetrics(GetDelegate(), abort_info))
267 return;
268
269 // If we did not receive any timing IPCs from the render process, we can't
270 // know for certain if the page was truly aborted before paint, or if the
271 // abort happened before we received the IPC from the render process. Thus, we
272 // do not log aborts for these page loads. Tracked page loads that receive no
273 // timing IPCs are tracked via the ERR_NO_IPCS_RECEIVED error code in the
274 // PageLoad.Events.InternalError histogram, so we can keep track of how often
275 // this happens.
276 if (page_load_metrics::IsEmpty(timing))
277 return;
278
279 if (timing.parse_timing->parse_start &&
280 abort_info.time_to_abort >= timing.parse_timing->parse_start &&
281 (!timing.parse_timing->parse_stop ||
282 timing.parse_timing->parse_stop >= abort_info.time_to_abort)) {
283 RecordAbortDuringParse(abort_info);
284 }
285 if (!timing.paint_timing->first_paint ||
286 timing.paint_timing->first_paint >= abort_info.time_to_abort) {
287 RecordAbortAfterCommitBeforePaint(abort_info);
288 }
289 }
290
OnFailedProvisionalLoad(const page_load_metrics::FailedProvisionalLoadInfo & failed_load_info)291 void AbortsPageLoadMetricsObserver::OnFailedProvisionalLoad(
292 const page_load_metrics::FailedProvisionalLoadInfo& failed_load_info) {
293 page_load_metrics::PageAbortInfo abort_info = GetPageAbortInfo(GetDelegate());
294 if (!ShouldTrackMetrics(GetDelegate(), abort_info))
295 return;
296
297 RecordAbortBeforeCommit(abort_info);
298 }
299