1 // Copyright 2016 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/document_write_page_load_metrics_observer.h"
6 #include "chrome/browser/browser_process.h"
7 #include "components/page_load_metrics/browser/page_load_metrics_util.h"
8 #include "services/metrics/public/cpp/ukm_builders.h"
9 #include "services/metrics/public/cpp/ukm_recorder.h"
10 #include "third_party/blink/public/common/loader/loading_behavior_flag.h"
11 
12 namespace internal {
13 const char kHistogramDocWriteBlockFirstContentfulPaint[] =
14     "PageLoad.Clients.DocWrite.Block.PaintTiming."
15     "NavigationToFirstContentfulPaint";
16 const char kHistogramDocWriteBlockParseStartToFirstContentfulPaint[] =
17     "PageLoad.Clients.DocWrite.Block.PaintTiming."
18     "ParseStartToFirstContentfulPaint";
19 const char kHistogramDocWriteBlockParseBlockedOnScriptLoad[] =
20     "PageLoad.Clients.DocWrite.Block.ParseTiming.ParseBlockedOnScriptLoad";
21 const char kHistogramDocWriteBlockParseBlockedOnScriptLoadDocumentWrite[] =
22     "PageLoad.Clients.DocWrite.Block.ParseTiming."
23     "ParseBlockedOnScriptLoadFromDocumentWrite";
24 const char kHistogramDocWriteBlockParseBlockedOnScriptExecution[] =
25     "PageLoad.Clients.DocWrite.Block.ParseTiming.ParseBlockedOnScriptExecution";
26 const char kHistogramDocWriteBlockParseBlockedOnScriptExecutionDocumentWrite[] =
27     "PageLoad.Clients.DocWrite.Block.ParseTiming."
28     "ParseBlockedOnScriptExecutionFromDocumentWrite";
29 const char kHistogramDocWriteBlockParseDuration[] =
30     "PageLoad.Clients.DocWrite.Block.ParseTiming.ParseDuration";
31 
32 const char kBackgroundHistogramDocWriteBlockParseBlockedOnScriptLoad[] =
33     "PageLoad.Clients.DocWrite.Block.ParseTiming.ParseBlockedOnScriptLoad."
34     "Background";
35 const char kBackgroundDocWriteBlockParseBlockedOnScriptLoadDocumentWrite[] =
36     "PageLoad.Clients.DocWrite.Block.ParseTiming."
37     "ParseBlockedOnScriptLoadFromDocumentWrite.Background";
38 const char kBackgroundHistogramDocWriteBlockParseDuration[] =
39     "PageLoad.Clients.DocWrite.Block.ParseTiming.ParseDuration.Background";
40 
41 const char kHistogramDocWriteBlockCount[] =
42     "PageLoad.Clients.DocWrite.Block.Count";
43 const char kHistogramDocWriteBlockReloadCount[] =
44     "PageLoad.Clients.DocWrite.Block.ReloadCount";
45 const char kHistogramDocWriteBlockLoadingBehavior[] =
46     "PageLoad.Clients.DocWrite.Block.DocumentWriteLoadingBehavior";
47 
48 }  // namespace internal
49 
OnFirstContentfulPaintInPage(const page_load_metrics::mojom::PageLoadTiming & timing)50 void DocumentWritePageLoadMetricsObserver::OnFirstContentfulPaintInPage(
51     const page_load_metrics::mojom::PageLoadTiming& timing) {
52   if (GetDelegate().GetMainFrameMetadata().behavior_flags &
53       blink::LoadingBehaviorFlag::kLoadingBehaviorDocumentWriteBlock) {
54     LogDocumentWriteBlockFirstContentfulPaint(timing);
55   }
56 }
57 
58 void DocumentWritePageLoadMetricsObserver::
OnFirstMeaningfulPaintInMainFrameDocument(const page_load_metrics::mojom::PageLoadTiming & timing)59     OnFirstMeaningfulPaintInMainFrameDocument(
60         const page_load_metrics::mojom::PageLoadTiming& timing) {
61   if (GetDelegate().GetMainFrameMetadata().behavior_flags &
62       blink::LoadingBehaviorFlag::kLoadingBehaviorDocumentWriteBlock) {
63     LogDocumentWriteBlockFirstMeaningfulPaint(timing);
64   }
65 }
66 
OnParseStop(const page_load_metrics::mojom::PageLoadTiming & timing)67 void DocumentWritePageLoadMetricsObserver::OnParseStop(
68     const page_load_metrics::mojom::PageLoadTiming& timing) {
69   if (GetDelegate().GetMainFrameMetadata().behavior_flags &
70       blink::LoadingBehaviorFlag::kLoadingBehaviorDocumentWriteBlock) {
71     LogDocumentWriteBlockParseStop(timing);
72   }
73 }
74 
75 // static
LogLoadingBehaviorMetrics(DocumentWritePageLoadMetricsObserver::DocumentWriteLoadingBehavior behavior,ukm::SourceId source_id)76 void DocumentWritePageLoadMetricsObserver::LogLoadingBehaviorMetrics(
77     DocumentWritePageLoadMetricsObserver::DocumentWriteLoadingBehavior behavior,
78     ukm::SourceId source_id) {
79   UMA_HISTOGRAM_ENUMERATION(
80       internal::kHistogramDocWriteBlockLoadingBehavior, behavior,
81       DocumentWritePageLoadMetricsObserver::LOADING_BEHAVIOR_MAX);
82 
83   // We only log the block and reload behaviors in UKM.
84   if (behavior != LOADING_BEHAVIOR_BLOCK &&
85       behavior != LOADING_BEHAVIOR_RELOAD) {
86     return;
87   }
88   ukm::builders::Intervention_DocumentWrite_ScriptBlock builder(source_id);
89   if (behavior == LOADING_BEHAVIOR_RELOAD)
90     builder.SetDisabled_Reload(true);
91   builder.Record(ukm::UkmRecorder::Get());
92 }
93 
OnLoadingBehaviorObserved(content::RenderFrameHost * rfh,int behavior_flags)94 void DocumentWritePageLoadMetricsObserver::OnLoadingBehaviorObserved(
95     content::RenderFrameHost* rfh,
96     int behavior_flags) {
97   if ((GetDelegate().GetMainFrameMetadata().behavior_flags &
98        blink::LoadingBehaviorFlag::kLoadingBehaviorDocumentWriteBlockReload) &&
99       !doc_write_block_reload_observed_) {
100     DCHECK(!(GetDelegate().GetMainFrameMetadata().behavior_flags &
101              blink::LoadingBehaviorFlag::kLoadingBehaviorDocumentWriteBlock));
102     UMA_HISTOGRAM_COUNTS_1M(internal::kHistogramDocWriteBlockReloadCount, 1);
103     LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_RELOAD,
104                               GetDelegate().GetPageUkmSourceId());
105     doc_write_block_reload_observed_ = true;
106   }
107   if ((GetDelegate().GetMainFrameMetadata().behavior_flags &
108        blink::LoadingBehaviorFlag::kLoadingBehaviorDocumentWriteBlock) &&
109       !doc_write_block_observed_) {
110     UMA_HISTOGRAM_BOOLEAN(internal::kHistogramDocWriteBlockCount, true);
111     LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_BLOCK,
112                               GetDelegate().GetPageUkmSourceId());
113     doc_write_block_observed_ = true;
114   }
115   if ((GetDelegate().GetMainFrameMetadata().behavior_flags &
116        blink::LoadingBehaviorFlag::
117            kLoadingBehaviorDocumentWriteBlockDifferentScheme) &&
118       !doc_write_same_site_diff_scheme_) {
119     LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_SAME_SITE_DIFF_SCHEME,
120                               GetDelegate().GetPageUkmSourceId());
121     doc_write_same_site_diff_scheme_ = true;
122   }
123 }
124 
125 // Note: The first meaningful paint calculation in the core observer filters
126 // out pages which had user interaction before the first meaningful paint.
127 // Because the counts of those instances are low (< 2%), just log everything
128 // here for simplicity. If this ends up being unreliable (the 2% is just from
129 // canary), the page_load_metrics API should be altered to return the values
130 // the consumer wants.
131 void DocumentWritePageLoadMetricsObserver::
LogDocumentWriteBlockFirstMeaningfulPaint(const page_load_metrics::mojom::PageLoadTiming & timing)132     LogDocumentWriteBlockFirstMeaningfulPaint(
133         const page_load_metrics::mojom::PageLoadTiming& timing) {
134   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
135           timing.paint_timing->first_meaningful_paint, GetDelegate())) {
136     PAGE_LOAD_HISTOGRAM(
137         "PageLoad.Clients.DocWrite.Block.Experimental.PaintTiming."
138         "ParseStartToFirstMeaningfulPaint",
139         timing.paint_timing->first_meaningful_paint.value() -
140             timing.parse_timing->parse_start.value());
141   }
142 }
143 
144 void DocumentWritePageLoadMetricsObserver::
LogDocumentWriteBlockFirstContentfulPaint(const page_load_metrics::mojom::PageLoadTiming & timing)145     LogDocumentWriteBlockFirstContentfulPaint(
146         const page_load_metrics::mojom::PageLoadTiming& timing) {
147   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
148           timing.paint_timing->first_contentful_paint, GetDelegate())) {
149     PAGE_LOAD_HISTOGRAM(internal::kHistogramDocWriteBlockFirstContentfulPaint,
150                         timing.paint_timing->first_contentful_paint.value());
151     PAGE_LOAD_HISTOGRAM(
152         internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint,
153         timing.paint_timing->first_contentful_paint.value() -
154             timing.parse_timing->parse_start.value());
155   }
156 }
157 
LogDocumentWriteBlockParseStop(const page_load_metrics::mojom::PageLoadTiming & timing)158 void DocumentWritePageLoadMetricsObserver::LogDocumentWriteBlockParseStop(
159     const page_load_metrics::mojom::PageLoadTiming& timing) {
160   base::TimeDelta parse_duration = timing.parse_timing->parse_stop.value() -
161                                    timing.parse_timing->parse_start.value();
162   if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
163           timing.parse_timing->parse_stop, GetDelegate())) {
164     PAGE_LOAD_HISTOGRAM(internal::kHistogramDocWriteBlockParseDuration,
165                         parse_duration);
166     PAGE_LOAD_HISTOGRAM(
167         internal::kHistogramDocWriteBlockParseBlockedOnScriptLoad,
168         timing.parse_timing->parse_blocked_on_script_load_duration.value());
169     PAGE_LOAD_HISTOGRAM(
170         internal::kHistogramDocWriteBlockParseBlockedOnScriptLoadDocumentWrite,
171         timing.parse_timing
172             ->parse_blocked_on_script_load_from_document_write_duration
173             .value());
174     PAGE_LOAD_HISTOGRAM(
175         internal::kHistogramDocWriteBlockParseBlockedOnScriptExecution,
176         timing.parse_timing->parse_blocked_on_script_execution_duration
177             .value());
178     PAGE_LOAD_HISTOGRAM(
179         internal::
180             kHistogramDocWriteBlockParseBlockedOnScriptExecutionDocumentWrite,
181         timing.parse_timing
182             ->parse_blocked_on_script_execution_from_document_write_duration
183             .value());
184 
185     ukm::builders::Intervention_DocumentWrite_ScriptBlock(
186         GetDelegate().GetPageUkmSourceId())
187         .SetParseTiming_ParseBlockedOnScriptLoadFromDocumentWrite(
188             timing.parse_timing
189                 ->parse_blocked_on_script_load_from_document_write_duration
190                 ->InMilliseconds())
191         .SetParseTiming_ParseBlockedOnScriptExecutionFromDocumentWrite(
192             timing.parse_timing
193                 ->parse_blocked_on_script_execution_from_document_write_duration
194                 ->InMilliseconds())
195         .Record(ukm::UkmRecorder::Get());
196   } else {
197     PAGE_LOAD_HISTOGRAM(
198         internal::kBackgroundHistogramDocWriteBlockParseDuration,
199         parse_duration);
200     PAGE_LOAD_HISTOGRAM(
201         internal::kBackgroundHistogramDocWriteBlockParseBlockedOnScriptLoad,
202         timing.parse_timing->parse_blocked_on_script_load_duration.value());
203     PAGE_LOAD_HISTOGRAM(
204         internal::kBackgroundDocWriteBlockParseBlockedOnScriptLoadDocumentWrite,
205         timing.parse_timing
206             ->parse_blocked_on_script_load_from_document_write_duration
207             .value());
208   }
209 }
210