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 "components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <memory>
10 #include <utility>
11 
12 #include "base/feature_list.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h"
15 #include "components/page_load_metrics/browser/page_load_metrics_util.h"
16 #include "content/public/common/process_type.h"
17 #include "net/http/http_response_headers.h"
18 #include "third_party/blink/public/common/input/web_gesture_event.h"
19 #include "third_party/blink/public/common/input/web_mouse_event.h"
20 #include "ui/base/page_transition_types.h"
21 #include "ui/events/blink/blink_features.h"
22 
23 namespace {
24 
25 // Used to generate a unique id when emitting the "Long Navigation to First
26 // Contentful Paint" trace event.
27 int g_num_trace_events_in_process = 0;
28 
29 // The threshold to emit a trace event is the 99th percentile
30 // of the histogram on Windows Stable as of Feb 26th, 2020.
31 constexpr base::TimeDelta kFirstContentfulPaintTraceThreshold =
32     base::TimeDelta::FromMilliseconds(12388);
33 
34 // TODO(bmcquade): If other observers want to log histograms based on load type,
35 // promote this enum to page_load_metrics_observer.h.
36 enum PageLoadType {
37   LOAD_TYPE_NONE = 0,
38   LOAD_TYPE_RELOAD,
39   LOAD_TYPE_FORWARD_BACK,
40   LOAD_TYPE_NEW_NAVIGATION
41 };
42 
GetPageLoadType(ui::PageTransition transition)43 PageLoadType GetPageLoadType(ui::PageTransition transition) {
44   if (transition & ui::PAGE_TRANSITION_FORWARD_BACK) {
45     return LOAD_TYPE_FORWARD_BACK;
46   }
47   if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD)) {
48     return LOAD_TYPE_RELOAD;
49   }
50   if (ui::PageTransitionIsNewNavigation(transition)) {
51     return LOAD_TYPE_NEW_NAVIGATION;
52   }
53   NOTREACHED() << "Received PageTransition with no matching PageLoadType.";
54   return LOAD_TYPE_NONE;
55 }
56 
RecordFirstMeaningfulPaintStatus(internal::FirstMeaningfulPaintStatus status)57 void RecordFirstMeaningfulPaintStatus(
58     internal::FirstMeaningfulPaintStatus status) {
59   UMA_HISTOGRAM_ENUMERATION(internal::kHistogramFirstMeaningfulPaintStatus,
60                             status,
61                             internal::FIRST_MEANINGFUL_PAINT_LAST_ENTRY);
62 }
63 
FirstInputDelayTraceData(const page_load_metrics::mojom::PageLoadTiming & timing)64 std::unique_ptr<base::trace_event::TracedValue> FirstInputDelayTraceData(
65     const page_load_metrics::mojom::PageLoadTiming& timing) {
66   std::unique_ptr<base::trace_event::TracedValue> data =
67       std::make_unique<base::trace_event::TracedValue>();
68   data->SetDouble(
69       "firstInputDelayInMilliseconds",
70       timing.interactive_timing->first_input_delay->InMillisecondsF());
71   data->SetDouble(
72       "navStartToFirstInputTimestampInMilliseconds",
73       timing.interactive_timing->first_input_timestamp->InMillisecondsF());
74   return data;
75 }
76 
77 // TODO(crbug/1097328): Remove collecting visits to support.google.com after
78 // language settings update fully launches.
79 #if defined(OS_CHROMEOS)
RecordVisitToLanguageSettingsSupportPage(const GURL & url)80 void RecordVisitToLanguageSettingsSupportPage(const GURL& url) {
81   if (url.is_empty() || !url.DomainIs("support.google.com"))
82     return;
83 
84   // Keep these pages in order with SettingsLanguagesSupportPage in enums.xml
85   std::vector<std::string> kSupportPages = {
86       "chrome/answer/173424?co=GENIE.Platform%3DDesktop",
87       "chromebook/answer/1059490",
88       "chromebook/answer/1059492",
89   };
90   const size_t num_pages = 3;
91   for (size_t i = 0; i < num_pages; ++i) {
92     if (url.spec().find(kSupportPages[i]) != std::string::npos) {
93       UMA_HISTOGRAM_ENUMERATION("ChromeOS.Settings.Languages.SupportPageVisits",
94                                 i, num_pages);
95       return;
96     }
97   }
98 }
99 #endif  // defined(OS_CHROMEOS)
100 
101 }  // namespace
102 
103 namespace internal {
104 
105 const char kHistogramDomContentLoaded[] =
106     "PageLoad.DocumentTiming.NavigationToDOMContentLoadedEventFired";
107 const char kBackgroundHistogramDomContentLoaded[] =
108     "PageLoad.DocumentTiming.NavigationToDOMContentLoadedEventFired.Background";
109 const char kHistogramLoad[] =
110     "PageLoad.DocumentTiming.NavigationToLoadEventFired";
111 const char kBackgroundHistogramLoad[] =
112     "PageLoad.DocumentTiming.NavigationToLoadEventFired.Background";
113 const char kHistogramFirstPaint[] =
114     "PageLoad.PaintTiming.NavigationToFirstPaint";
115 const char kBackgroundHistogramFirstPaint[] =
116     "PageLoad.PaintTiming.NavigationToFirstPaint.Background";
117 const char kHistogramFirstImagePaint[] =
118     "PageLoad.PaintTiming.NavigationToFirstImagePaint";
119 const char kBackgroundHistogramFirstImagePaint[] =
120     "PageLoad.PaintTiming.NavigationToFirstImagePaint.Background";
121 const char kHistogramFirstContentfulPaint[] =
122     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint";
123 const char kBackgroundHistogramFirstContentfulPaint[] =
124     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.Background";
125 const char kHistogramFirstContentfulPaintInitiatingProcess[] =
126     "PageLoad.Internal.PaintTiming.NavigationToFirstContentfulPaint."
127     "InitiatingProcess";
128 const char kHistogramFirstMeaningfulPaint[] =
129     "PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint";
130 const char kHistogramLargestContentfulPaint[] =
131     "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2";
132 const char kHistogramLargestContentfulPaintContentType[] =
133     "PageLoad.Internal.PaintTiming.LargestContentfulPaint.ContentType";
134 const char kHistogramLargestContentfulPaintMainFrame[] =
135     "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.MainFrame";
136 const char kHistogramLargestContentfulPaintMainFrameContentType[] =
137     "PageLoad.Internal.PaintTiming.LargestContentfulPaint.MainFrame."
138     "ContentType";
139 // TODO(crbug.com/1045640): Stop reporting these obsolete versions after some
140 // time.
141 const char kDeprecatedHistogramLargestContentfulPaint[] =
142     "PageLoad.PaintTiming.NavigationToLargestContentfulPaint";
143 const char kHistogramExperimentalLargestContentfulPaintContentType[] =
144     "PageLoad.Internal.PaintTiming.ExperimentalLargestContentfulPaint."
145     "ContentType";
146 const char kDeprecatedHistogramLargestContentfulPaintMainFrame[] =
147     "PageLoad.PaintTiming.NavigationToLargestContentfulPaint."
148     "MainFrame";
149 const char kHistogramExperimentalLargestContentfulPaintMainFrameContentType[] =
150     "PageLoad.Internal.PaintTiming.ExperimentalLargestContentfulPaint."
151     "MainFrame."
152     "ContentType";
153 const char kHistogramFirstInputDelay[] =
154     "PageLoad.InteractiveTiming.FirstInputDelay4";
155 const char kHistogramFirstInputTimestamp[] =
156     "PageLoad.InteractiveTiming.FirstInputTimestamp4";
157 const char kHistogramLongestInputDelay[] =
158     "PageLoad.InteractiveTiming.LongestInputDelay4";
159 const char kHistogramLongestInputTimestamp[] =
160     "PageLoad.InteractiveTiming.LongestInputTimestamp4";
161 const char kHistogramParseStartToFirstMeaningfulPaint[] =
162     "PageLoad.Experimental.PaintTiming.ParseStartToFirstMeaningfulPaint";
163 const char kHistogramParseStartToFirstContentfulPaint[] =
164     "PageLoad.PaintTiming.ParseStartToFirstContentfulPaint";
165 const char kBackgroundHistogramParseStartToFirstContentfulPaint[] =
166     "PageLoad.PaintTiming.ParseStartToFirstContentfulPaint.Background";
167 const char kHistogramParseStart[] =
168     "PageLoad.ParseTiming.NavigationToParseStart";
169 const char kBackgroundHistogramParseStart[] =
170     "PageLoad.ParseTiming.NavigationToParseStart.Background";
171 const char kHistogramParseDuration[] = "PageLoad.ParseTiming.ParseDuration";
172 const char kBackgroundHistogramParseDuration[] =
173     "PageLoad.ParseTiming.ParseDuration.Background";
174 const char kHistogramParseBlockedOnScriptLoad[] =
175     "PageLoad.ParseTiming.ParseBlockedOnScriptLoad";
176 const char kBackgroundHistogramParseBlockedOnScriptLoad[] =
177     "PageLoad.ParseTiming.ParseBlockedOnScriptLoad.Background";
178 const char kHistogramParseBlockedOnScriptLoadDocumentWrite[] =
179     "PageLoad.ParseTiming.ParseBlockedOnScriptLoadFromDocumentWrite";
180 const char kBackgroundHistogramParseBlockedOnScriptLoadDocumentWrite[] =
181     "PageLoad.ParseTiming.ParseBlockedOnScriptLoadFromDocumentWrite."
182     "Background";
183 const char kHistogramParseBlockedOnScriptExecution[] =
184     "PageLoad.ParseTiming.ParseBlockedOnScriptExecution";
185 const char kHistogramParseBlockedOnScriptExecutionDocumentWrite[] =
186     "PageLoad.ParseTiming.ParseBlockedOnScriptExecutionFromDocumentWrite";
187 
188 const char kHistogramFirstContentfulPaintNoStore[] =
189     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.NoStore";
190 
191 const char kHistogramFirstContentfulPaintHiddenWhileFlushing[] =
192     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.HiddenWhileFlushing";
193 
194 const char kHistogramLoadTypeFirstContentfulPaintReload[] =
195     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
196     "Reload";
197 const char kHistogramLoadTypeFirstContentfulPaintReloadByGesture[] =
198     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
199     "Reload.UserGesture";
200 const char kHistogramLoadTypeFirstContentfulPaintForwardBack[] =
201     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
202     "ForwardBackNavigation";
203 const char kHistogramLoadTypeFirstContentfulPaintForwardBackNoStore[] =
204     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
205     "ForwardBackNavigation.NoStore";
206 const char kHistogramLoadTypeFirstContentfulPaintNewNavigation[] =
207     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
208     "NewNavigation";
209 
210 const char kHistogramPageTimingForegroundDuration[] =
211     "PageLoad.PageTiming.ForegroundDuration";
212 const char kHistogramPageTimingForegroundDurationAfterPaint[] =
213     "PageLoad.PageTiming.ForegroundDuration.AfterPaint";
214 const char kHistogramPageTimingForegroundDurationNoCommit[] =
215     "PageLoad.PageTiming.ForegroundDuration.NoCommit";
216 const char kHistogramPageTimingForegroundDurationWithPaint[] =
217     "PageLoad.PageTiming.ForegroundDuration.WithPaint";
218 const char kHistogramPageTimingForegroundDurationWithoutPaint[] =
219     "PageLoad.PageTiming.ForegroundDuration.WithoutPaint";
220 
221 const char kHistogramLoadTypeParseStartReload[] =
222     "PageLoad.ParseTiming.NavigationToParseStart.LoadType.Reload";
223 const char kHistogramLoadTypeParseStartForwardBack[] =
224     "PageLoad.ParseTiming.NavigationToParseStart.LoadType."
225     "ForwardBackNavigation";
226 const char kHistogramLoadTypeParseStartForwardBackNoStore[] =
227     "PageLoad.ParseTiming.NavigationToParseStart.LoadType."
228     "ForwardBackNavigation.NoStore";
229 const char kHistogramLoadTypeParseStartNewNavigation[] =
230     "PageLoad.ParseTiming.NavigationToParseStart.LoadType.NewNavigation";
231 
232 const char kHistogramFirstForeground[] =
233     "PageLoad.PageTiming.NavigationToFirstForeground";
234 
235 const char kHistogramFailedProvisionalLoad[] =
236     "PageLoad.PageTiming.NavigationToFailedProvisionalLoad";
237 
238 const char kHistogramUserGestureNavigationToForwardBack[] =
239     "PageLoad.PageTiming.ForegroundDuration.PageEndReason."
240     "ForwardBackNavigation.UserGesture";
241 
242 const char kHistogramForegroundToFirstPaint[] =
243     "PageLoad.PaintTiming.ForegroundToFirstPaint";
244 const char kHistogramForegroundToFirstContentfulPaint[] =
245     "PageLoad.PaintTiming.ForegroundToFirstContentfulPaint";
246 
247 const char kHistogramFirstContentfulPaintUserInitiated[] =
248     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.UserInitiated";
249 
250 const char kHistogramFirstMeaningfulPaintStatus[] =
251     "PageLoad.Experimental.PaintTiming.FirstMeaningfulPaintStatus";
252 
253 const char kHistogramFirstNonScrollInputAfterFirstPaint[] =
254     "PageLoad.InputTiming.NavigationToFirstNonScroll.AfterPaint";
255 const char kHistogramFirstScrollInputAfterFirstPaint[] =
256     "PageLoad.InputTiming.NavigationToFirstScroll.AfterPaint";
257 
258 const char kHistogramPageLoadTotalBytes[] =
259     "PageLoad.Experimental.Bytes.Total2";
260 const char kHistogramPageLoadNetworkBytes[] =
261     "PageLoad.Experimental.Bytes.Network";
262 const char kHistogramPageLoadCacheBytes[] =
263     "PageLoad.Experimental.Bytes.Cache2";
264 const char kHistogramPageLoadNetworkBytesIncludingHeaders[] =
265     "PageLoad.Experimental.Bytes.NetworkIncludingHeaders";
266 const char kHistogramPageLoadUnfinishedBytes[] =
267     "PageLoad.Experimental.Bytes.Unfinished";
268 
269 const char kHistogramPageLoadCpuTotalUsage[] = "PageLoad.Cpu.TotalUsage";
270 const char kHistogramPageLoadCpuTotalUsageForegrounded[] =
271     "PageLoad.Cpu.TotalUsageForegrounded";
272 
273 const char kHistogramLoadTypeTotalBytesForwardBack[] =
274     "PageLoad.Experimental.Bytes.Total2.LoadType.ForwardBackNavigation";
275 const char kHistogramLoadTypeNetworkBytesForwardBack[] =
276     "PageLoad.Experimental.Bytes.Network.LoadType.ForwardBackNavigation";
277 const char kHistogramLoadTypeCacheBytesForwardBack[] =
278     "PageLoad.Experimental.Bytes.Cache2.LoadType.ForwardBackNavigation";
279 
280 const char kHistogramLoadTypeTotalBytesReload[] =
281     "PageLoad.Experimental.Bytes.Total2.LoadType.Reload";
282 const char kHistogramLoadTypeNetworkBytesReload[] =
283     "PageLoad.Experimental.Bytes.Network.LoadType.Reload";
284 const char kHistogramLoadTypeCacheBytesReload[] =
285     "PageLoad.Experimental.Bytes.Cache2.LoadType.Reload";
286 
287 const char kHistogramLoadTypeTotalBytesNewNavigation[] =
288     "PageLoad.Experimental.Bytes.Total2.LoadType.NewNavigation";
289 const char kHistogramLoadTypeNetworkBytesNewNavigation[] =
290     "PageLoad.Experimental.Bytes.Network.LoadType.NewNavigation";
291 const char kHistogramLoadTypeCacheBytesNewNavigation[] =
292     "PageLoad.Experimental.Bytes.Cache2.LoadType.NewNavigation";
293 
294 const char kHistogramTotalCompletedResources[] =
295     "PageLoad.Experimental.CompletedResources.Total2";
296 const char kHistogramNetworkCompletedResources[] =
297     "PageLoad.Experimental.CompletedResources.Network";
298 const char kHistogramCacheCompletedResources[] =
299     "PageLoad.Experimental.CompletedResources.Cache2";
300 
301 const char kHistogramInputToNavigation[] =
302     "PageLoad.Experimental.InputTiming.InputToNavigationStart";
303 const char kBackgroundHistogramInputToNavigation[] =
304     "PageLoad.Experimental.InputTiming.InputToNavigationStart.Background";
305 const char kHistogramInputToNavigationLinkClick[] =
306     "PageLoad.Experimental.InputTiming.InputToNavigationStart.FromLinkClick";
307 const char kHistogramInputToNavigationOmnibox[] =
308     "PageLoad.Experimental.InputTiming.InputToNavigationStart.FromOmnibox";
309 const char kHistogramInputToFirstPaint[] =
310     "PageLoad.Experimental.PaintTiming.InputToFirstPaint";
311 const char kBackgroundHistogramInputToFirstPaint[] =
312     "PageLoad.Experimental.PaintTiming.InputToFirstPaint.Background";
313 const char kHistogramInputToFirstContentfulPaint[] =
314     "PageLoad.Experimental.PaintTiming.InputToFirstContentfulPaint";
315 const char kBackgroundHistogramInputToFirstContentfulPaint[] =
316     "PageLoad.Experimental.PaintTiming.InputToFirstContentfulPaint.Background";
317 
318 const char kHistogramBackForwardCacheEvent[] =
319     "PageLoad.BackForwardCache.Event";
320 
321 // Navigation metrics from the navigation start.
322 const char kHistogramNavigationTimingNavigationStartToFirstRequestStart[] =
323     "PageLoad.Experimental.NavigationTiming.NavigationStartToFirstRequestStart";
324 const char kHistogramNavigationTimingNavigationStartToFirstResponseStart[] =
325     "PageLoad.Experimental.NavigationTiming."
326     "NavigationStartToFirstResponseStart";
327 const char kHistogramNavigationTimingNavigationStartToFirstLoaderCallback[] =
328     "PageLoad.Experimental.NavigationTiming."
329     "NavigationStartToFirstLoaderCallback";
330 const char kHistogramNavigationTimingNavigationStartToFinalRequestStart[] =
331     "PageLoad.Experimental.NavigationTiming.NavigationStartToFinalRequestStart";
332 const char kHistogramNavigationTimingNavigationStartToFinalResponseStart[] =
333     "PageLoad.Experimental.NavigationTiming."
334     "NavigationStartToFinalResponseStart";
335 const char kHistogramNavigationTimingNavigationStartToFinalLoaderCallback[] =
336     "PageLoad.Experimental.NavigationTiming."
337     "NavigationStartToFinalLoaderCallback";
338 const char kHistogramNavigationTimingNavigationStartToNavigationCommitSent[] =
339     "PageLoad.Experimental.NavigationTiming."
340     "NavigationStartToNavigationCommitSent";
341 
342 // Navigation metrics between milestones.
343 const char kHistogramNavigationTimingFirstRequestStartToFirstResponseStart[] =
344     "PageLoad.Experimental.NavigationTiming."
345     "FirstRequestStartToFirstResponseStart";
346 const char kHistogramNavigationTimingFirstResponseStartToFirstLoaderCallback[] =
347     "PageLoad.Experimental.NavigationTiming."
348     "FirstResponseStartToFirstLoaderCallback";
349 const char kHistogramNavigationTimingFinalRequestStartToFinalResponseStart[] =
350     "PageLoad.Experimental.NavigationTiming."
351     "FinalRequestStartToFinalResponseStart";
352 const char kHistogramNavigationTimingFinalResponseStartToFinalLoaderCallback[] =
353     "PageLoad.Experimental.NavigationTiming."
354     "FinalResponseStartToFinalLoaderCallback";
355 const char
356     kHistogramNavigationTimingFinalLoaderCallbackToNavigationCommitSent[] =
357         "PageLoad.Experimental.NavigationTiming."
358         "FinalLoaderCallbackToNavigationCommitSent";
359 
360 // 103 Early Hints metrics for experiment (https://crbug.com/1093693).
361 const char kHistogramEarlyHintsFirstRequestStartToEarlyHints[] =
362     "PageLoad.Experimental.EarlyHints.FirstRequestStartToEarlyHints";
363 const char kHistogramEarlyHintsFinalRequestStartToEarlyHints[] =
364     "PageLoad.Experimental.EarlyHints.FinalRequestStartToEarlyHints";
365 const char kHistogramEarlyHintsEarlyHintsToFinalResponseStart[] =
366     "PageLoad.Experimental.EarlyHints.EarlyHintsToFinalResponseStart";
367 
368 }  // namespace internal
369 
UmaPageLoadMetricsObserver()370 UmaPageLoadMetricsObserver::UmaPageLoadMetricsObserver()
371     : transition_(ui::PAGE_TRANSITION_LINK),
372       was_no_store_main_resource_(false),
373       num_cache_resources_(0),
374       num_network_resources_(0),
375       cache_bytes_(0),
376       network_bytes_(0),
377       network_bytes_including_headers_(0),
378       redirect_chain_size_(0) {}
379 
~UmaPageLoadMetricsObserver()380 UmaPageLoadMetricsObserver::~UmaPageLoadMetricsObserver() {}
381 
382 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
OnRedirect(content::NavigationHandle * navigation_handle)383 UmaPageLoadMetricsObserver::OnRedirect(
384     content::NavigationHandle* navigation_handle) {
385   redirect_chain_size_++;
386   return CONTINUE_OBSERVING;
387 }
388 
389 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
OnCommit(content::NavigationHandle * navigation_handle,ukm::SourceId source_id)390 UmaPageLoadMetricsObserver::OnCommit(
391     content::NavigationHandle* navigation_handle,
392     ukm::SourceId source_id) {
393   transition_ = navigation_handle->GetPageTransition();
394   const net::HttpResponseHeaders* headers =
395       navigation_handle->GetResponseHeaders();
396   if (headers) {
397     was_no_store_main_resource_ =
398         headers->HasHeaderValue("cache-control", "no-store");
399   }
400   UMA_HISTOGRAM_COUNTS_100("PageLoad.Navigation.RedirectChainLength",
401                            redirect_chain_size_);
402   navigation_handle_timing_ = navigation_handle->GetNavigationHandleTiming();
403 
404   // TODO(crbug/1097328): Remove collecting visits to support.google.com after
405   // language settings update fully launches.
406 #if defined(OS_CHROMEOS)
407   RecordVisitToLanguageSettingsSupportPage(navigation_handle->GetURL());
408 #endif  // defined(OS_CHROMEOS)
409   return CONTINUE_OBSERVING;
410 }
411 
OnDomContentLoadedEventStart(const page_load_metrics::mojom::PageLoadTiming & timing)412 void UmaPageLoadMetricsObserver::OnDomContentLoadedEventStart(
413     const page_load_metrics::mojom::PageLoadTiming& timing) {
414   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
415           timing.document_timing->dom_content_loaded_event_start,
416           GetDelegate())) {
417     PAGE_LOAD_HISTOGRAM(
418         internal::kHistogramDomContentLoaded,
419         timing.document_timing->dom_content_loaded_event_start.value());
420   } else {
421     PAGE_LOAD_HISTOGRAM(
422         internal::kBackgroundHistogramDomContentLoaded,
423         timing.document_timing->dom_content_loaded_event_start.value());
424   }
425 }
426 
OnLoadEventStart(const page_load_metrics::mojom::PageLoadTiming & timing)427 void UmaPageLoadMetricsObserver::OnLoadEventStart(
428     const page_load_metrics::mojom::PageLoadTiming& timing) {
429   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
430           timing.document_timing->load_event_start, GetDelegate())) {
431     PAGE_LOAD_HISTOGRAM(internal::kHistogramLoad,
432                         timing.document_timing->load_event_start.value());
433   } else {
434     PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramLoad,
435                         timing.document_timing->load_event_start.value());
436   }
437 }
438 
OnFirstPaintInPage(const page_load_metrics::mojom::PageLoadTiming & timing)439 void UmaPageLoadMetricsObserver::OnFirstPaintInPage(
440     const page_load_metrics::mojom::PageLoadTiming& timing) {
441   first_paint_ = GetDelegate().GetNavigationStart() +
442                  timing.paint_timing->first_paint.value();
443   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
444           timing.paint_timing->first_paint, GetDelegate())) {
445     PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstPaint,
446                         timing.paint_timing->first_paint.value());
447 
448     if (timing.input_to_navigation_start) {
449       PAGE_LOAD_HISTOGRAM(internal::kHistogramInputToFirstPaint,
450                           timing.input_to_navigation_start.value() +
451                               timing.paint_timing->first_paint.value());
452     }
453   } else {
454     PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstPaint,
455                         timing.paint_timing->first_paint.value());
456     if (timing.input_to_navigation_start) {
457       PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramInputToFirstPaint,
458                           timing.input_to_navigation_start.value() +
459                               timing.paint_timing->first_paint.value());
460     }
461   }
462 
463   if (page_load_metrics::WasStartedInBackgroundOptionalEventInForeground(
464           timing.paint_timing->first_paint, GetDelegate())) {
465     PAGE_LOAD_HISTOGRAM(internal::kHistogramForegroundToFirstPaint,
466                         timing.paint_timing->first_paint.value() -
467                             GetDelegate().GetFirstForegroundTime().value());
468   }
469 }
470 
OnFirstImagePaintInPage(const page_load_metrics::mojom::PageLoadTiming & timing)471 void UmaPageLoadMetricsObserver::OnFirstImagePaintInPage(
472     const page_load_metrics::mojom::PageLoadTiming& timing) {
473   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
474           timing.paint_timing->first_image_paint, GetDelegate())) {
475     PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstImagePaint,
476                         timing.paint_timing->first_image_paint.value());
477   } else {
478     PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstImagePaint,
479                         timing.paint_timing->first_image_paint.value());
480   }
481 }
482 
OnFirstContentfulPaintInPage(const page_load_metrics::mojom::PageLoadTiming & timing)483 void UmaPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
484     const page_load_metrics::mojom::PageLoadTiming& timing) {
485   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
486           timing.paint_timing->first_contentful_paint, GetDelegate())) {
487     PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaint,
488                         timing.paint_timing->first_contentful_paint.value());
489     PAGE_LOAD_HISTOGRAM(internal::kHistogramParseStartToFirstContentfulPaint,
490                         timing.paint_timing->first_contentful_paint.value() -
491                             timing.parse_timing->parse_start.value());
492 
493     // Emit a trace event to highlight a long navigation to first contentful
494     // paint.
495     if (timing.paint_timing->first_contentful_paint >
496         kFirstContentfulPaintTraceThreshold) {
497       base::TimeTicks navigation_start = GetDelegate().GetNavigationStart();
498       TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
499           "latency", "Long Navigation to First Contentful Paint",
500           TRACE_ID_LOCAL(g_num_trace_events_in_process), navigation_start);
501       TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
502           "latency", "Long Navigation to First Contentful Paint",
503           TRACE_ID_LOCAL(g_num_trace_events_in_process),
504           navigation_start +
505               timing.paint_timing->first_contentful_paint.value());
506       g_num_trace_events_in_process++;
507     }
508 
509     UMA_HISTOGRAM_ENUMERATION(
510         internal::kHistogramFirstContentfulPaintInitiatingProcess,
511         GetDelegate().GetUserInitiatedInfo().browser_initiated
512             ? content::PROCESS_TYPE_BROWSER
513             : content::PROCESS_TYPE_RENDERER,
514         content::PROCESS_TYPE_CONTENT_END);
515 
516     if (was_no_store_main_resource_) {
517       PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintNoStore,
518                           timing.paint_timing->first_contentful_paint.value());
519     }
520 
521     // TODO(bmcquade): consider adding a histogram that uses
522     // UserInputInfo.user_input_event.
523     if (GetDelegate().GetUserInitiatedInfo().browser_initiated ||
524         GetDelegate().GetUserInitiatedInfo().user_gesture) {
525       PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintUserInitiated,
526                           timing.paint_timing->first_contentful_paint.value());
527     }
528 
529     if (timing.input_to_navigation_start) {
530       PAGE_LOAD_HISTOGRAM(internal::kHistogramInputToNavigation,
531                           timing.input_to_navigation_start.value());
532       PAGE_LOAD_HISTOGRAM(
533           internal::kHistogramInputToFirstContentfulPaint,
534           timing.input_to_navigation_start.value() +
535               timing.paint_timing->first_contentful_paint.value());
536 
537       if (ui::PageTransitionCoreTypeIs(transition_, ui::PAGE_TRANSITION_LINK)) {
538         PAGE_LOAD_HISTOGRAM(internal::kHistogramInputToNavigationLinkClick,
539                             timing.input_to_navigation_start.value());
540       } else if (ui::PageTransitionCoreTypeIs(transition_,
541                                               ui::PAGE_TRANSITION_GENERATED) ||
542                  ui::PageTransitionCoreTypeIs(transition_,
543                                               ui::PAGE_TRANSITION_TYPED)) {
544         PAGE_LOAD_HISTOGRAM(internal::kHistogramInputToNavigationOmnibox,
545                             timing.input_to_navigation_start.value());
546       }
547     }
548 
549     if (GetDelegate().GetFirstBackgroundTime()) {
550       // We were started in the foreground, and got FCP while in foreground, but
551       // became hidden while propagating the FCP value from Blink into the PLM
552       // observer. In this case, we will have missed the FCP UKM value, since it
553       // is logged in UkmPageLoadMetricsObserver::OnHidden.
554       PAGE_LOAD_HISTOGRAM(
555           internal::kHistogramFirstContentfulPaintHiddenWhileFlushing,
556           timing.paint_timing->first_contentful_paint.value());
557     }
558 
559     switch (GetPageLoadType(transition_)) {
560       case LOAD_TYPE_RELOAD:
561         PAGE_LOAD_HISTOGRAM(
562             internal::kHistogramLoadTypeFirstContentfulPaintReload,
563             timing.paint_timing->first_contentful_paint.value());
564         // TODO(bmcquade): consider adding a histogram that uses
565         // UserInputInfo.user_input_event.
566         if (GetDelegate().GetUserInitiatedInfo().browser_initiated ||
567             GetDelegate().GetUserInitiatedInfo().user_gesture) {
568           PAGE_LOAD_HISTOGRAM(
569               internal::kHistogramLoadTypeFirstContentfulPaintReloadByGesture,
570               timing.paint_timing->first_contentful_paint.value());
571         }
572         break;
573       case LOAD_TYPE_FORWARD_BACK:
574         PAGE_LOAD_HISTOGRAM(
575             internal::kHistogramLoadTypeFirstContentfulPaintForwardBack,
576             timing.paint_timing->first_contentful_paint.value());
577         if (was_no_store_main_resource_) {
578           PAGE_LOAD_HISTOGRAM(
579               internal::
580                   kHistogramLoadTypeFirstContentfulPaintForwardBackNoStore,
581               timing.paint_timing->first_contentful_paint.value());
582         }
583         break;
584       case LOAD_TYPE_NEW_NAVIGATION:
585         PAGE_LOAD_HISTOGRAM(
586             internal::kHistogramLoadTypeFirstContentfulPaintNewNavigation,
587             timing.paint_timing->first_contentful_paint.value());
588         break;
589       case LOAD_TYPE_NONE:
590         NOTREACHED();
591         break;
592     }
593   } else {
594     PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstContentfulPaint,
595                         timing.paint_timing->first_contentful_paint.value());
596     PAGE_LOAD_HISTOGRAM(
597         internal::kBackgroundHistogramParseStartToFirstContentfulPaint,
598         timing.paint_timing->first_contentful_paint.value() -
599             timing.parse_timing->parse_start.value());
600     if (timing.input_to_navigation_start) {
601       PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramInputToNavigation,
602                           timing.input_to_navigation_start.value());
603       PAGE_LOAD_HISTOGRAM(
604           internal::kBackgroundHistogramInputToFirstContentfulPaint,
605           timing.input_to_navigation_start.value() +
606               timing.paint_timing->first_contentful_paint.value());
607     }
608   }
609 
610   if (page_load_metrics::WasStartedInBackgroundOptionalEventInForeground(
611           timing.paint_timing->first_contentful_paint, GetDelegate())) {
612     PAGE_LOAD_HISTOGRAM(internal::kHistogramForegroundToFirstContentfulPaint,
613                         timing.paint_timing->first_contentful_paint.value() -
614                             GetDelegate().GetFirstForegroundTime().value());
615   }
616 }
617 
OnFirstMeaningfulPaintInMainFrameDocument(const page_load_metrics::mojom::PageLoadTiming & timing)618 void UmaPageLoadMetricsObserver::OnFirstMeaningfulPaintInMainFrameDocument(
619     const page_load_metrics::mojom::PageLoadTiming& timing) {
620   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
621           timing.paint_timing->first_meaningful_paint, GetDelegate())) {
622     PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstMeaningfulPaint,
623                         timing.paint_timing->first_meaningful_paint.value());
624     PAGE_LOAD_HISTOGRAM(internal::kHistogramParseStartToFirstMeaningfulPaint,
625                         timing.paint_timing->first_meaningful_paint.value() -
626                             timing.parse_timing->parse_start.value());
627     RecordFirstMeaningfulPaintStatus(internal::FIRST_MEANINGFUL_PAINT_RECORDED);
628   } else {
629     RecordFirstMeaningfulPaintStatus(
630         internal::FIRST_MEANINGFUL_PAINT_BACKGROUNDED);
631   }
632 }
633 
OnFirstInputInPage(const page_load_metrics::mojom::PageLoadTiming & timing)634 void UmaPageLoadMetricsObserver::OnFirstInputInPage(
635     const page_load_metrics::mojom::PageLoadTiming& timing) {
636   if (!page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
637           timing.interactive_timing->first_input_timestamp, GetDelegate())) {
638     return;
639   }
640   UMA_HISTOGRAM_CUSTOM_TIMES(
641       internal::kHistogramFirstInputDelay,
642       timing.interactive_timing->first_input_delay.value(),
643       base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(60),
644       50);
645   PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstInputTimestamp,
646                       timing.interactive_timing->first_input_timestamp.value());
647   TRACE_EVENT_MARK_WITH_TIMESTAMP1(
648       "loading", "FirstInputDelay::AllFrames::UMA",
649       GetDelegate().GetNavigationStart() +
650           timing.interactive_timing->first_input_timestamp.value(),
651       "data", FirstInputDelayTraceData(timing));
652 }
653 
OnParseStart(const page_load_metrics::mojom::PageLoadTiming & timing)654 void UmaPageLoadMetricsObserver::OnParseStart(
655     const page_load_metrics::mojom::PageLoadTiming& timing) {
656   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
657           timing.parse_timing->parse_start, GetDelegate())) {
658     PAGE_LOAD_HISTOGRAM(internal::kHistogramParseStart,
659                         timing.parse_timing->parse_start.value());
660 
661     switch (GetPageLoadType(transition_)) {
662       case LOAD_TYPE_RELOAD:
663         PAGE_LOAD_HISTOGRAM(internal::kHistogramLoadTypeParseStartReload,
664                             timing.parse_timing->parse_start.value());
665         break;
666       case LOAD_TYPE_FORWARD_BACK:
667         PAGE_LOAD_HISTOGRAM(internal::kHistogramLoadTypeParseStartForwardBack,
668                             timing.parse_timing->parse_start.value());
669         if (was_no_store_main_resource_) {
670           PAGE_LOAD_HISTOGRAM(
671               internal::kHistogramLoadTypeParseStartForwardBackNoStore,
672               timing.parse_timing->parse_start.value());
673         }
674         break;
675       case LOAD_TYPE_NEW_NAVIGATION:
676         PAGE_LOAD_HISTOGRAM(internal::kHistogramLoadTypeParseStartNewNavigation,
677                             timing.parse_timing->parse_start.value());
678         break;
679       case LOAD_TYPE_NONE:
680         NOTREACHED();
681         break;
682     }
683   } else {
684     PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramParseStart,
685                         timing.parse_timing->parse_start.value());
686   }
687 }
688 
OnParseStop(const page_load_metrics::mojom::PageLoadTiming & timing)689 void UmaPageLoadMetricsObserver::OnParseStop(
690     const page_load_metrics::mojom::PageLoadTiming& timing) {
691   base::TimeDelta parse_duration = timing.parse_timing->parse_stop.value() -
692                                    timing.parse_timing->parse_start.value();
693   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
694           timing.parse_timing->parse_stop, GetDelegate())) {
695     PAGE_LOAD_HISTOGRAM(internal::kHistogramParseDuration, parse_duration);
696     PAGE_LOAD_HISTOGRAM(
697         internal::kHistogramParseBlockedOnScriptLoad,
698         timing.parse_timing->parse_blocked_on_script_load_duration.value());
699     PAGE_LOAD_HISTOGRAM(
700         internal::kHistogramParseBlockedOnScriptLoadDocumentWrite,
701         timing.parse_timing
702             ->parse_blocked_on_script_load_from_document_write_duration
703             .value());
704     PAGE_LOAD_HISTOGRAM(
705         internal::kHistogramParseBlockedOnScriptExecution,
706         timing.parse_timing->parse_blocked_on_script_execution_duration
707             .value());
708     PAGE_LOAD_HISTOGRAM(
709         internal::kHistogramParseBlockedOnScriptExecutionDocumentWrite,
710         timing.parse_timing
711             ->parse_blocked_on_script_execution_from_document_write_duration
712             .value());
713   } else {
714     PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramParseDuration,
715                         parse_duration);
716     PAGE_LOAD_HISTOGRAM(
717         internal::kBackgroundHistogramParseBlockedOnScriptLoad,
718         timing.parse_timing->parse_blocked_on_script_load_duration.value());
719     PAGE_LOAD_HISTOGRAM(
720         internal::kBackgroundHistogramParseBlockedOnScriptLoadDocumentWrite,
721         timing.parse_timing
722             ->parse_blocked_on_script_load_from_document_write_duration
723             .value());
724   }
725 }
726 
OnComplete(const page_load_metrics::mojom::PageLoadTiming & timing)727 void UmaPageLoadMetricsObserver::OnComplete(
728     const page_load_metrics::mojom::PageLoadTiming& timing) {
729   RecordNavigationTimingHistograms();
730   RecordTimingHistograms(timing);
731   RecordByteAndResourceHistograms(timing);
732   RecordCpuUsageHistograms();
733   RecordForegroundDurationHistograms(timing, base::TimeTicks());
734 }
735 
736 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
FlushMetricsOnAppEnterBackground(const page_load_metrics::mojom::PageLoadTiming & timing)737 UmaPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
738     const page_load_metrics::mojom::PageLoadTiming& timing) {
739   // FlushMetricsOnAppEnterBackground is invoked on Android in cases where the
740   // app is about to be backgrounded, as part of the Activity.onPause()
741   // flow. After this method is invoked, Chrome may be killed without further
742   // notification, so we record final metrics collected up to this point.
743   if (GetDelegate().DidCommit()) {
744     RecordNavigationTimingHistograms();
745     RecordTimingHistograms(timing);
746     RecordByteAndResourceHistograms(timing);
747     RecordCpuUsageHistograms();
748   }
749   RecordForegroundDurationHistograms(timing, base::TimeTicks::Now());
750   return STOP_OBSERVING;
751 }
752 
OnFailedProvisionalLoad(const page_load_metrics::FailedProvisionalLoadInfo & failed_load_info)753 void UmaPageLoadMetricsObserver::OnFailedProvisionalLoad(
754     const page_load_metrics::FailedProvisionalLoadInfo& failed_load_info) {
755   // Only handle actual failures; provisional loads that failed due to another
756   // committed load or due to user action are recorded in
757   // AbortsPageLoadMetricsObserver.
758   if (failed_load_info.error != net::OK &&
759       failed_load_info.error != net::ERR_ABORTED) {
760     if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
761             failed_load_info.time_to_failed_provisional_load, GetDelegate())) {
762       PAGE_LOAD_HISTOGRAM(internal::kHistogramFailedProvisionalLoad,
763                           failed_load_info.time_to_failed_provisional_load);
764     }
765   }
766   // Provide an empty PageLoadTiming, since we don't have any timing metrics
767   // for failed provisional loads.
768   RecordForegroundDurationHistograms(page_load_metrics::mojom::PageLoadTiming(),
769                                      base::TimeTicks());
770 }
771 
OnUserInput(const blink::WebInputEvent & event,const page_load_metrics::mojom::PageLoadTiming & timing)772 void UmaPageLoadMetricsObserver::OnUserInput(
773     const blink::WebInputEvent& event,
774     const page_load_metrics::mojom::PageLoadTiming& timing) {
775   base::TimeTicks now;
776 
777   if (first_paint_.is_null())
778     return;
779 
780   // Track clicks after first paint for possible click burst.
781   click_tracker_.OnUserInput(event);
782 
783   if (!received_non_scroll_input_after_first_paint_) {
784     if (event.GetType() == blink::WebInputEvent::Type::kGestureTap ||
785         event.GetType() == blink::WebInputEvent::Type::kMouseUp) {
786       received_non_scroll_input_after_first_paint_ = true;
787       if (now.is_null())
788         now = base::TimeTicks::Now();
789       PAGE_LOAD_HISTOGRAM(
790           internal::kHistogramFirstNonScrollInputAfterFirstPaint,
791           now - first_paint_);
792     }
793   }
794   if (!received_scroll_input_after_first_paint_ &&
795       event.GetType() == blink::WebInputEvent::Type::kGestureScrollBegin) {
796     received_scroll_input_after_first_paint_ = true;
797     if (now.is_null())
798       now = base::TimeTicks::Now();
799     PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstScrollInputAfterFirstPaint,
800                         now - first_paint_);
801   }
802 }
803 
OnResourceDataUseObserved(content::RenderFrameHost * rfh,const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> & resources)804 void UmaPageLoadMetricsObserver::OnResourceDataUseObserved(
805     content::RenderFrameHost* rfh,
806     const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
807         resources) {
808   for (auto const& resource : resources) {
809     if (resource->is_complete) {
810       if (resource->cache_type ==
811           page_load_metrics::mojom::CacheType::kNotCached) {
812         network_bytes_ += resource->encoded_body_length;
813         num_network_resources_++;
814       } else {
815         cache_bytes_ += resource->encoded_body_length;
816         num_cache_resources_++;
817       }
818     }
819     network_bytes_including_headers_ += resource->delta_bytes;
820   }
821 }
822 
RecordNavigationTimingHistograms()823 void UmaPageLoadMetricsObserver::RecordNavigationTimingHistograms() {
824   const base::TimeTicks navigation_start_time =
825       GetDelegate().GetNavigationStart();
826   const content::NavigationHandleTiming& timing = navigation_handle_timing_;
827 
828   // Record metrics for navigation only when all relevant milestones are
829   // recorded and in the expected order. It is allowed that they have the same
830   // value for some cases (e.g., internal redirection for HSTS).
831   if (navigation_start_time.is_null() ||
832       timing.first_request_start_time.is_null() ||
833       timing.first_response_start_time.is_null() ||
834       timing.first_loader_callback_time.is_null() ||
835       timing.final_request_start_time.is_null() ||
836       timing.final_response_start_time.is_null() ||
837       timing.final_loader_callback_time.is_null() ||
838       timing.navigation_commit_sent_time.is_null()) {
839     return;
840   }
841   // TODO(https://crbug.com/1076710): Change these early-returns to DCHECKs
842   // after the issue 1076710 is fixed.
843   if (navigation_start_time > timing.first_request_start_time ||
844       timing.first_request_start_time > timing.first_response_start_time ||
845       timing.first_response_start_time > timing.first_loader_callback_time ||
846       timing.first_loader_callback_time > timing.navigation_commit_sent_time) {
847     return;
848   }
849   if (navigation_start_time > timing.final_request_start_time ||
850       timing.final_request_start_time > timing.final_response_start_time ||
851       timing.final_response_start_time > timing.final_loader_callback_time ||
852       timing.final_loader_callback_time > timing.navigation_commit_sent_time) {
853     return;
854   }
855   DCHECK_LE(timing.first_request_start_time, timing.final_request_start_time);
856   DCHECK_LE(timing.first_response_start_time, timing.final_response_start_time);
857   DCHECK_LE(timing.first_loader_callback_time,
858             timing.final_loader_callback_time);
859 
860   // Record the elapsed time from the navigation start milestone.
861   PAGE_LOAD_HISTOGRAM(
862       internal::kHistogramNavigationTimingNavigationStartToFirstRequestStart,
863       timing.first_request_start_time - navigation_start_time);
864   PAGE_LOAD_HISTOGRAM(
865       internal::kHistogramNavigationTimingNavigationStartToFirstResponseStart,
866       timing.first_response_start_time - navigation_start_time);
867   PAGE_LOAD_HISTOGRAM(
868       internal::kHistogramNavigationTimingNavigationStartToFirstLoaderCallback,
869       timing.first_loader_callback_time - navigation_start_time);
870 
871   PAGE_LOAD_HISTOGRAM(
872       internal::kHistogramNavigationTimingNavigationStartToFinalRequestStart,
873       timing.final_request_start_time - navigation_start_time);
874   PAGE_LOAD_HISTOGRAM(
875       internal::kHistogramNavigationTimingNavigationStartToFinalResponseStart,
876       timing.final_response_start_time - navigation_start_time);
877   PAGE_LOAD_HISTOGRAM(
878       internal::kHistogramNavigationTimingNavigationStartToFinalLoaderCallback,
879       timing.final_loader_callback_time - navigation_start_time);
880 
881   PAGE_LOAD_HISTOGRAM(
882       internal::kHistogramNavigationTimingNavigationStartToNavigationCommitSent,
883       timing.navigation_commit_sent_time - navigation_start_time);
884 
885   // Record the intervals between milestones.
886   PAGE_LOAD_HISTOGRAM(
887       internal::kHistogramNavigationTimingFirstRequestStartToFirstResponseStart,
888       timing.first_response_start_time - timing.first_request_start_time);
889   PAGE_LOAD_HISTOGRAM(
890       internal::
891           kHistogramNavigationTimingFirstResponseStartToFirstLoaderCallback,
892       timing.first_loader_callback_time - timing.first_response_start_time);
893 
894   PAGE_LOAD_HISTOGRAM(
895       internal::kHistogramNavigationTimingFinalRequestStartToFinalResponseStart,
896       timing.final_response_start_time - timing.final_request_start_time);
897   PAGE_LOAD_HISTOGRAM(
898       internal::
899           kHistogramNavigationTimingFinalResponseStartToFinalLoaderCallback,
900       timing.final_loader_callback_time - timing.final_response_start_time);
901 
902   PAGE_LOAD_HISTOGRAM(
903       internal::
904           kHistogramNavigationTimingFinalLoaderCallbackToNavigationCommitSent,
905       timing.navigation_commit_sent_time - timing.final_loader_callback_time);
906 
907   // Record the following intervals for the 103 Early Hints experiment
908   // (https://crbug.com/1093693).
909   // - The first request start to the 103 response,
910   // - The final request start to the 103 response, and the 103 response to the
911   //   final response,
912   // Note that multiple 103 responses can be served per request. These metrics
913   // use the first 103 response as the timing.
914   if (!timing.early_hints_for_first_request_time.is_null()) {
915     PAGE_LOAD_HISTOGRAM(
916         internal::kHistogramEarlyHintsFirstRequestStartToEarlyHints,
917         timing.first_request_start_time -
918             timing.early_hints_for_first_request_time);
919   }
920   if (!timing.early_hints_for_final_request_time.is_null()) {
921     PAGE_LOAD_HISTOGRAM(
922         internal::kHistogramEarlyHintsFinalRequestStartToEarlyHints,
923         timing.final_request_start_time -
924             timing.early_hints_for_final_request_time);
925     PAGE_LOAD_HISTOGRAM(
926         internal::kHistogramEarlyHintsEarlyHintsToFinalResponseStart,
927         timing.early_hints_for_final_request_time -
928             timing.final_response_start_time);
929   }
930 }
931 
932 // This method records values for metrics that were not recorded during any
933 // other event, or records failure status for metrics that have not been
934 // collected yet. This is meant to be called at the end of a page lifetime, for
935 // example, when the user is navigating away from the page.
RecordTimingHistograms(const page_load_metrics::mojom::PageLoadTiming & main_frame_timing)936 void UmaPageLoadMetricsObserver::RecordTimingHistograms(
937     const page_load_metrics::mojom::PageLoadTiming& main_frame_timing) {
938   // Log time to first foreground / time to first background. Log counts that we
939   // started a relevant page load in the foreground / background.
940   if (!GetDelegate().StartedInForeground() &&
941       GetDelegate().GetFirstForegroundTime()) {
942     PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstForeground,
943                         GetDelegate().GetFirstForegroundTime().value());
944   }
945 
946   const page_load_metrics::ContentfulPaintTimingInfo&
947       main_frame_largest_contentful_paint =
948           GetDelegate()
949               .GetLargestContentfulPaintHandler()
950               .MainFrameLargestContentfulPaint();
951   if (main_frame_largest_contentful_paint.ContainsValidTime() &&
952       WasStartedInForegroundOptionalEventInForeground(
953           main_frame_largest_contentful_paint.Time(), GetDelegate())) {
954     PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaintMainFrame,
955                         main_frame_largest_contentful_paint.Time().value());
956     UMA_HISTOGRAM_ENUMERATION(
957         internal::kHistogramLargestContentfulPaintMainFrameContentType,
958         main_frame_largest_contentful_paint.Type());
959   }
960 
961   const page_load_metrics::ContentfulPaintTimingInfo&
962       all_frames_largest_contentful_paint =
963           GetDelegate()
964               .GetLargestContentfulPaintHandler()
965               .MergeMainFrameAndSubframes();
966   if (all_frames_largest_contentful_paint.ContainsValidTime() &&
967       WasStartedInForegroundOptionalEventInForeground(
968           all_frames_largest_contentful_paint.Time(), GetDelegate())) {
969     PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaint,
970                         all_frames_largest_contentful_paint.Time().value());
971     UMA_HISTOGRAM_ENUMERATION(
972         internal::kHistogramLargestContentfulPaintContentType,
973         all_frames_largest_contentful_paint.Type());
974     TRACE_EVENT_MARK_WITH_TIMESTAMP1(
975         "loading", "NavStartToLargestContentfulPaint::AllFrames::UMA",
976         GetDelegate().GetNavigationStart() +
977             all_frames_largest_contentful_paint.Time().value(),
978         "data", all_frames_largest_contentful_paint.DataAsTraceValue());
979   }
980 
981   const page_load_metrics::ContentfulPaintTimingInfo&
982       main_frame_experimental_largest_contentful_paint =
983           GetDelegate()
984               .GetExperimentalLargestContentfulPaintHandler()
985               .MainFrameLargestContentfulPaint();
986   if (main_frame_experimental_largest_contentful_paint.ContainsValidTime() &&
987       WasStartedInForegroundOptionalEventInForeground(
988           main_frame_experimental_largest_contentful_paint.Time(),
989           GetDelegate())) {
990     PAGE_LOAD_HISTOGRAM(
991         internal::kDeprecatedHistogramLargestContentfulPaintMainFrame,
992         main_frame_experimental_largest_contentful_paint.Time().value());
993     UMA_HISTOGRAM_ENUMERATION(
994         internal::
995             kHistogramExperimentalLargestContentfulPaintMainFrameContentType,
996         main_frame_experimental_largest_contentful_paint.Type());
997   }
998 
999   const page_load_metrics::ContentfulPaintTimingInfo&
1000       all_frames_experimental_largest_contentful_paint =
1001           GetDelegate()
1002               .GetExperimentalLargestContentfulPaintHandler()
1003               .MergeMainFrameAndSubframes();
1004   if (all_frames_experimental_largest_contentful_paint.ContainsValidTime() &&
1005       WasStartedInForegroundOptionalEventInForeground(
1006           all_frames_experimental_largest_contentful_paint.Time(),
1007           GetDelegate())) {
1008     PAGE_LOAD_HISTOGRAM(
1009         internal::kDeprecatedHistogramLargestContentfulPaint,
1010         all_frames_experimental_largest_contentful_paint.Time().value());
1011     UMA_HISTOGRAM_ENUMERATION(
1012         internal::kHistogramExperimentalLargestContentfulPaintContentType,
1013         all_frames_experimental_largest_contentful_paint.Type());
1014     TRACE_EVENT_MARK_WITH_TIMESTAMP1(
1015         "loading",
1016         "NavStartToExperimentalLargestContentfulPaint::AllFrames::UMA",
1017         GetDelegate().GetNavigationStart() +
1018             all_frames_experimental_largest_contentful_paint.Time().value(),
1019         "data",
1020         all_frames_experimental_largest_contentful_paint.DataAsTraceValue());
1021   }
1022 
1023   if (main_frame_timing.paint_timing->first_paint &&
1024       !main_frame_timing.paint_timing->first_meaningful_paint) {
1025     RecordFirstMeaningfulPaintStatus(
1026         main_frame_timing.paint_timing->first_contentful_paint
1027             ? internal::FIRST_MEANINGFUL_PAINT_DID_NOT_REACH_NETWORK_STABLE
1028             : internal::
1029                   FIRST_MEANINGFUL_PAINT_DID_NOT_REACH_FIRST_CONTENTFUL_PAINT);
1030   }
1031 
1032   if (main_frame_timing.interactive_timing->longest_input_timestamp) {
1033     DCHECK(main_frame_timing.interactive_timing->longest_input_delay);
1034     UMA_HISTOGRAM_CUSTOM_TIMES(
1035         internal::kHistogramLongestInputDelay,
1036         main_frame_timing.interactive_timing->longest_input_delay.value(),
1037         base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(60),
1038         50);
1039     PAGE_LOAD_HISTOGRAM(
1040         internal::kHistogramLongestInputTimestamp,
1041         main_frame_timing.interactive_timing->longest_input_timestamp.value());
1042   }
1043 }
1044 
RecordForegroundDurationHistograms(const page_load_metrics::mojom::PageLoadTiming & timing,base::TimeTicks app_background_time)1045 void UmaPageLoadMetricsObserver::RecordForegroundDurationHistograms(
1046     const page_load_metrics::mojom::PageLoadTiming& timing,
1047     base::TimeTicks app_background_time) {
1048   base::Optional<base::TimeDelta> foreground_duration =
1049       page_load_metrics::GetInitialForegroundDuration(GetDelegate(),
1050                                                       app_background_time);
1051   if (!foreground_duration)
1052     return;
1053 
1054   if (GetDelegate().DidCommit()) {
1055     PAGE_LOAD_LONG_HISTOGRAM(internal::kHistogramPageTimingForegroundDuration,
1056                              foreground_duration.value());
1057     if (timing.paint_timing->first_paint &&
1058         timing.paint_timing->first_paint < foreground_duration) {
1059       PAGE_LOAD_LONG_HISTOGRAM(
1060           internal::kHistogramPageTimingForegroundDurationAfterPaint,
1061           foreground_duration.value() -
1062               timing.paint_timing->first_paint.value());
1063       PAGE_LOAD_LONG_HISTOGRAM(
1064           internal::kHistogramPageTimingForegroundDurationWithPaint,
1065           foreground_duration.value());
1066     } else {
1067       PAGE_LOAD_LONG_HISTOGRAM(
1068           internal::kHistogramPageTimingForegroundDurationWithoutPaint,
1069           foreground_duration.value());
1070     }
1071   } else {
1072     PAGE_LOAD_LONG_HISTOGRAM(
1073         internal::kHistogramPageTimingForegroundDurationNoCommit,
1074         foreground_duration.value());
1075   }
1076 
1077   if (GetDelegate().GetPageEndReason() == page_load_metrics::END_FORWARD_BACK &&
1078       GetDelegate().GetUserInitiatedInfo().user_gesture &&
1079       !GetDelegate().GetUserInitiatedInfo().browser_initiated &&
1080       GetDelegate().GetPageEndTime() <= foreground_duration) {
1081     PAGE_LOAD_HISTOGRAM(internal::kHistogramUserGestureNavigationToForwardBack,
1082                         GetDelegate().GetPageEndTime().value());
1083   }
1084 }
1085 
OnCpuTimingUpdate(content::RenderFrameHost * subframe_rfh,const page_load_metrics::mojom::CpuTiming & timing)1086 void UmaPageLoadMetricsObserver::OnCpuTimingUpdate(
1087     content::RenderFrameHost* subframe_rfh,
1088     const page_load_metrics::mojom::CpuTiming& timing) {
1089   total_cpu_usage_ += timing.task_time;
1090 
1091   if (GetDelegate().GetVisibilityTracker().currently_in_foreground()) {
1092     foreground_cpu_usage_ += timing.task_time;
1093   }
1094 }
1095 
RecordByteAndResourceHistograms(const page_load_metrics::mojom::PageLoadTiming & timing)1096 void UmaPageLoadMetricsObserver::RecordByteAndResourceHistograms(
1097     const page_load_metrics::mojom::PageLoadTiming& timing) {
1098   DCHECK_GE(network_bytes_, 0);
1099   DCHECK_GE(cache_bytes_, 0);
1100   int64_t total_bytes = network_bytes_ + cache_bytes_;
1101 
1102   PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadNetworkBytes,
1103                        network_bytes_);
1104   PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadCacheBytes, cache_bytes_);
1105   PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadTotalBytes, total_bytes);
1106   PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadNetworkBytesIncludingHeaders,
1107                        network_bytes_including_headers_);
1108 
1109   size_t unfinished_bytes = 0;
1110   for (auto const& kv :
1111        GetDelegate().GetResourceTracker().unfinished_resources())
1112     unfinished_bytes += kv.second->received_data_length;
1113   PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadUnfinishedBytes,
1114                        unfinished_bytes);
1115 
1116   switch (GetPageLoadType(transition_)) {
1117     case LOAD_TYPE_RELOAD:
1118       PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeNetworkBytesReload,
1119                            network_bytes_);
1120       PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeCacheBytesReload,
1121                            cache_bytes_);
1122       PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeTotalBytesReload,
1123                            total_bytes);
1124       break;
1125     case LOAD_TYPE_FORWARD_BACK:
1126       PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeNetworkBytesForwardBack,
1127                            network_bytes_);
1128       PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeCacheBytesForwardBack,
1129                            cache_bytes_);
1130       PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeTotalBytesForwardBack,
1131                            total_bytes);
1132       break;
1133     case LOAD_TYPE_NEW_NAVIGATION:
1134       PAGE_BYTES_HISTOGRAM(
1135           internal::kHistogramLoadTypeNetworkBytesNewNavigation,
1136           network_bytes_);
1137       PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeCacheBytesNewNavigation,
1138                            cache_bytes_);
1139       PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeTotalBytesNewNavigation,
1140                            total_bytes);
1141       break;
1142     case LOAD_TYPE_NONE:
1143       NOTREACHED();
1144       break;
1145   }
1146 
1147   PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramNetworkCompletedResources,
1148                                 num_network_resources_);
1149   PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramCacheCompletedResources,
1150                                 num_cache_resources_);
1151   PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramTotalCompletedResources,
1152                                 num_cache_resources_ + num_network_resources_);
1153 
1154   click_tracker_.RecordClickBurst(GetDelegate().GetPageUkmSourceId());
1155 }
1156 
RecordCpuUsageHistograms()1157 void UmaPageLoadMetricsObserver::RecordCpuUsageHistograms() {
1158   PAGE_LOAD_HISTOGRAM(internal::kHistogramPageLoadCpuTotalUsage,
1159                       total_cpu_usage_);
1160   PAGE_LOAD_HISTOGRAM(internal::kHistogramPageLoadCpuTotalUsageForegrounded,
1161                       foreground_cpu_usage_);
1162 }
1163 
1164 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
OnEnterBackForwardCache(const page_load_metrics::mojom::PageLoadTiming & timing)1165 UmaPageLoadMetricsObserver::OnEnterBackForwardCache(
1166     const page_load_metrics::mojom::PageLoadTiming& timing) {
1167   UMA_HISTOGRAM_ENUMERATION(
1168       internal::kHistogramBackForwardCacheEvent,
1169       internal::PageLoadBackForwardCacheEvent::kEnterBackForwardCache);
1170   return PageLoadMetricsObserver::OnEnterBackForwardCache(timing);
1171 }
1172 
OnRestoreFromBackForwardCache(const page_load_metrics::mojom::PageLoadTiming & timing,content::NavigationHandle * navigation_handle)1173 void UmaPageLoadMetricsObserver::OnRestoreFromBackForwardCache(
1174     const page_load_metrics::mojom::PageLoadTiming& timing,
1175     content::NavigationHandle* navigation_handle) {
1176   // This never reaches yet because OnEnterBackForwardCache returns
1177   // STOP_OBSERVING.
1178   // TODO(hajimehoshi): After changing OnEnterBackForwardCache to continue
1179   // observation, remove the above comment.
1180   UMA_HISTOGRAM_ENUMERATION(
1181       internal::kHistogramBackForwardCacheEvent,
1182       internal::PageLoadBackForwardCacheEvent::kRestoreFromBackForwardCache);
1183 }
1184