OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 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 "chrome/browser/page_load_metrics/page_load_tracker.h" | 5 #include "chrome/browser/page_load_metrics/page_load_tracker.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <ostream> | 8 #include <ostream> |
9 #include <string> | 9 #include <string> |
10 #include <utility> | 10 #include <utility> |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 // second. | 123 // second. |
124 bool EventsInOrder(const base::Optional<base::TimeDelta>& first, | 124 bool EventsInOrder(const base::Optional<base::TimeDelta>& first, |
125 const base::Optional<base::TimeDelta>& second) { | 125 const base::Optional<base::TimeDelta>& second) { |
126 if (!second) { | 126 if (!second) { |
127 return true; | 127 return true; |
128 } | 128 } |
129 return first && first <= second; | 129 return first && first <= second; |
130 } | 130 } |
131 | 131 |
132 internal::PageLoadTimingStatus IsValidPageLoadTiming( | 132 internal::PageLoadTimingStatus IsValidPageLoadTiming( |
133 const PageLoadTiming& timing) { | 133 const mojom::PageLoadTiming& timing) { |
134 if (timing.IsEmpty()) | 134 if (page_load_metrics::IsEmpty(timing)) |
135 return internal::INVALID_EMPTY_TIMING; | 135 return internal::INVALID_EMPTY_TIMING; |
136 | 136 |
137 // If we have a non-empty timing, it should always have a navigation start. | 137 // If we have a non-empty timing, it should always have a navigation start. |
138 if (timing.navigation_start.is_null()) { | 138 if (timing.navigation_start.is_null()) { |
139 LOG(ERROR) << "Received null navigation_start."; | 139 LOG(ERROR) << "Received null navigation_start."; |
140 return internal::INVALID_NULL_NAVIGATION_START; | 140 return internal::INVALID_NULL_NAVIGATION_START; |
141 } | 141 } |
142 | 142 |
143 // Verify proper ordering between the various timings. | 143 // Verify proper ordering between the various timings. |
144 | 144 |
145 if (!EventsInOrder(timing.response_start, timing.parse_timing.parse_start)) { | 145 if (!EventsInOrder(timing.response_start, timing.parse_timing->parse_start)) { |
146 // We sometimes get a zero response_start with a non-zero parse start. See | 146 // We sometimes get a zero response_start with a non-zero parse start. See |
147 // crbug.com/590212. | 147 // crbug.com/590212. |
148 LOG(ERROR) << "Invalid response_start " << timing.response_start | 148 LOG(ERROR) << "Invalid response_start " << timing.response_start |
149 << " for parse_start " << timing.parse_timing.parse_start; | 149 << " for parse_start " << timing.parse_timing->parse_start; |
150 // When browser-side navigation is enabled, we sometimes encounter this | 150 // When browser-side navigation is enabled, we sometimes encounter this |
151 // error case. For now, we disable reporting of this error, since most | 151 // error case. For now, we disable reporting of this error, since most |
152 // PageLoadMetricsObservers don't care about response_start and we want to | 152 // PageLoadMetricsObservers don't care about response_start and we want to |
153 // see how much closer fixing this error will get us to page load metrics | 153 // see how much closer fixing this error will get us to page load metrics |
154 // being consistent with and without browser side navigation enabled. See | 154 // being consistent with and without browser side navigation enabled. See |
155 // crbug.com/716587 for more details. | 155 // crbug.com/716587 for more details. |
156 // | 156 // |
157 // return internal::INVALID_ORDER_RESPONSE_START_PARSE_START; | 157 // return internal::INVALID_ORDER_RESPONSE_START_PARSE_START; |
158 } | 158 } |
159 | 159 |
160 if (!EventsInOrder(timing.parse_timing.parse_start, | 160 if (!EventsInOrder(timing.parse_timing->parse_start, |
161 timing.parse_timing.parse_stop)) { | 161 timing.parse_timing->parse_stop)) { |
162 LOG(ERROR) << "Invalid parse_start " << timing.parse_timing.parse_start | 162 LOG(ERROR) << "Invalid parse_start " << timing.parse_timing->parse_start |
163 << " for parse_stop " << timing.parse_timing.parse_stop; | 163 << " for parse_stop " << timing.parse_timing->parse_stop; |
164 return internal::INVALID_ORDER_PARSE_START_PARSE_STOP; | 164 return internal::INVALID_ORDER_PARSE_START_PARSE_STOP; |
165 } | 165 } |
166 | 166 |
167 if (timing.parse_timing.parse_stop) { | 167 if (timing.parse_timing->parse_stop) { |
168 const base::TimeDelta parse_duration = | 168 const base::TimeDelta parse_duration = |
169 timing.parse_timing.parse_stop.value() - | 169 timing.parse_timing->parse_stop.value() - |
170 timing.parse_timing.parse_start.value(); | 170 timing.parse_timing->parse_start.value(); |
171 if (timing.parse_timing.parse_blocked_on_script_load_duration > | 171 if (timing.parse_timing->parse_blocked_on_script_load_duration > |
172 parse_duration) { | 172 parse_duration) { |
173 LOG(ERROR) << "Invalid parse_blocked_on_script_load_duration " | 173 LOG(ERROR) << "Invalid parse_blocked_on_script_load_duration " |
174 << timing.parse_timing.parse_blocked_on_script_load_duration | 174 << timing.parse_timing->parse_blocked_on_script_load_duration |
175 << " for parse duration " << parse_duration; | 175 << " for parse duration " << parse_duration; |
176 return internal::INVALID_SCRIPT_LOAD_LONGER_THAN_PARSE; | 176 return internal::INVALID_SCRIPT_LOAD_LONGER_THAN_PARSE; |
177 } | 177 } |
178 if (timing.parse_timing.parse_blocked_on_script_execution_duration > | 178 if (timing.parse_timing->parse_blocked_on_script_execution_duration > |
179 parse_duration) { | 179 parse_duration) { |
180 LOG(ERROR) | 180 LOG(ERROR) |
181 << "Invalid parse_blocked_on_script_execution_duration " | 181 << "Invalid parse_blocked_on_script_execution_duration " |
182 << timing.parse_timing.parse_blocked_on_script_execution_duration | 182 << timing.parse_timing->parse_blocked_on_script_execution_duration |
183 << " for parse duration " << parse_duration; | 183 << " for parse duration " << parse_duration; |
184 return internal::INVALID_SCRIPT_EXEC_LONGER_THAN_PARSE; | 184 return internal::INVALID_SCRIPT_EXEC_LONGER_THAN_PARSE; |
185 } | 185 } |
186 } | 186 } |
187 | 187 |
188 if (timing.parse_timing | 188 if (timing.parse_timing |
189 .parse_blocked_on_script_load_from_document_write_duration > | 189 ->parse_blocked_on_script_load_from_document_write_duration > |
190 timing.parse_timing.parse_blocked_on_script_load_duration) { | 190 timing.parse_timing->parse_blocked_on_script_load_duration) { |
191 LOG(ERROR) | 191 LOG(ERROR) |
192 << "Invalid parse_blocked_on_script_load_from_document_write_duration " | 192 << "Invalid parse_blocked_on_script_load_from_document_write_duration " |
193 << timing.parse_timing | 193 << timing.parse_timing |
194 .parse_blocked_on_script_load_from_document_write_duration | 194 ->parse_blocked_on_script_load_from_document_write_duration |
195 << " for parse_blocked_on_script_load_duration " | 195 << " for parse_blocked_on_script_load_duration " |
196 << timing.parse_timing.parse_blocked_on_script_load_duration; | 196 << timing.parse_timing->parse_blocked_on_script_load_duration; |
197 return internal::INVALID_SCRIPT_LOAD_DOC_WRITE_LONGER_THAN_SCRIPT_LOAD; | 197 return internal::INVALID_SCRIPT_LOAD_DOC_WRITE_LONGER_THAN_SCRIPT_LOAD; |
198 } | 198 } |
199 | 199 |
200 if (timing.parse_timing | 200 if (timing.parse_timing |
201 .parse_blocked_on_script_execution_from_document_write_duration > | 201 ->parse_blocked_on_script_execution_from_document_write_duration > |
202 timing.parse_timing.parse_blocked_on_script_execution_duration) { | 202 timing.parse_timing->parse_blocked_on_script_execution_duration) { |
203 LOG(ERROR) | 203 LOG(ERROR) |
204 << "Invalid " | 204 << "Invalid " |
205 "parse_blocked_on_script_execution_from_document_write_duration " | 205 "parse_blocked_on_script_execution_from_document_write_duration " |
206 << timing.parse_timing | 206 << timing.parse_timing |
207 .parse_blocked_on_script_execution_from_document_write_duration | 207 ->parse_blocked_on_script_execution_from_document_write_duration |
208 << " for parse_blocked_on_script_execution_duration " | 208 << " for parse_blocked_on_script_execution_duration " |
209 << timing.parse_timing.parse_blocked_on_script_execution_duration; | 209 << timing.parse_timing->parse_blocked_on_script_execution_duration; |
210 return internal::INVALID_SCRIPT_EXEC_DOC_WRITE_LONGER_THAN_SCRIPT_EXEC; | 210 return internal::INVALID_SCRIPT_EXEC_DOC_WRITE_LONGER_THAN_SCRIPT_EXEC; |
211 } | 211 } |
212 | 212 |
213 if (!EventsInOrder(timing.parse_timing.parse_stop, | 213 if (!EventsInOrder(timing.parse_timing->parse_stop, |
214 timing.document_timing.dom_content_loaded_event_start)) { | 214 timing.document_timing->dom_content_loaded_event_start)) { |
215 LOG(ERROR) << "Invalid parse_stop " << timing.parse_timing.parse_stop | 215 LOG(ERROR) << "Invalid parse_stop " << timing.parse_timing->parse_stop |
216 << " for dom_content_loaded_event_start " | 216 << " for dom_content_loaded_event_start " |
217 << timing.document_timing.dom_content_loaded_event_start; | 217 << timing.document_timing->dom_content_loaded_event_start; |
218 return internal::INVALID_ORDER_PARSE_STOP_DOM_CONTENT_LOADED; | 218 return internal::INVALID_ORDER_PARSE_STOP_DOM_CONTENT_LOADED; |
219 } | 219 } |
220 | 220 |
221 if (!EventsInOrder(timing.document_timing.dom_content_loaded_event_start, | 221 if (!EventsInOrder(timing.document_timing->dom_content_loaded_event_start, |
222 timing.document_timing.load_event_start)) { | 222 timing.document_timing->load_event_start)) { |
223 LOG(ERROR) << "Invalid dom_content_loaded_event_start " | 223 LOG(ERROR) << "Invalid dom_content_loaded_event_start " |
224 << timing.document_timing.dom_content_loaded_event_start | 224 << timing.document_timing->dom_content_loaded_event_start |
225 << " for load_event_start " | 225 << " for load_event_start " |
226 << timing.document_timing.load_event_start; | 226 << timing.document_timing->load_event_start; |
227 return internal::INVALID_ORDER_DOM_CONTENT_LOADED_LOAD; | 227 return internal::INVALID_ORDER_DOM_CONTENT_LOADED_LOAD; |
228 } | 228 } |
229 | 229 |
230 if (!EventsInOrder(timing.parse_timing.parse_start, | 230 if (!EventsInOrder(timing.parse_timing->parse_start, |
231 timing.document_timing.first_layout)) { | 231 timing.document_timing->first_layout)) { |
232 LOG(ERROR) << "Invalid parse_start " << timing.parse_timing.parse_start | 232 LOG(ERROR) << "Invalid parse_start " << timing.parse_timing->parse_start |
233 << " for first_layout " << timing.document_timing.first_layout; | 233 << " for first_layout " << timing.document_timing->first_layout; |
234 return internal::INVALID_ORDER_PARSE_START_FIRST_LAYOUT; | 234 return internal::INVALID_ORDER_PARSE_START_FIRST_LAYOUT; |
235 } | 235 } |
236 | 236 |
237 if (!EventsInOrder(timing.document_timing.first_layout, | 237 if (!EventsInOrder(timing.document_timing->first_layout, |
238 timing.paint_timing.first_paint)) { | 238 timing.paint_timing->first_paint)) { |
239 // This can happen when we process an XHTML document that doesn't contain | 239 // This can happen when we process an XHTML document that doesn't contain |
240 // well formed XML. See crbug.com/627607. | 240 // well formed XML. See crbug.com/627607. |
241 DLOG(ERROR) << "Invalid first_layout " | 241 DLOG(ERROR) << "Invalid first_layout " |
242 << timing.document_timing.first_layout << " for first_paint " | 242 << timing.document_timing->first_layout << " for first_paint " |
243 << timing.paint_timing.first_paint; | 243 << timing.paint_timing->first_paint; |
244 return internal::INVALID_ORDER_FIRST_LAYOUT_FIRST_PAINT; | 244 return internal::INVALID_ORDER_FIRST_LAYOUT_FIRST_PAINT; |
245 } | 245 } |
246 | 246 |
247 if (!EventsInOrder(timing.paint_timing.first_paint, | 247 if (!EventsInOrder(timing.paint_timing->first_paint, |
248 timing.paint_timing.first_text_paint)) { | 248 timing.paint_timing->first_text_paint)) { |
249 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 249 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint |
250 << " for first_text_paint " | 250 << " for first_text_paint " |
251 << timing.paint_timing.first_text_paint; | 251 << timing.paint_timing->first_text_paint; |
252 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_TEXT_PAINT; | 252 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_TEXT_PAINT; |
253 } | 253 } |
254 | 254 |
255 if (!EventsInOrder(timing.paint_timing.first_paint, | 255 if (!EventsInOrder(timing.paint_timing->first_paint, |
256 timing.paint_timing.first_image_paint)) { | 256 timing.paint_timing->first_image_paint)) { |
257 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 257 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint |
258 << " for first_image_paint " | 258 << " for first_image_paint " |
259 << timing.paint_timing.first_image_paint; | 259 << timing.paint_timing->first_image_paint; |
260 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_IMAGE_PAINT; | 260 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_IMAGE_PAINT; |
261 } | 261 } |
262 | 262 |
263 if (!EventsInOrder(timing.paint_timing.first_paint, | 263 if (!EventsInOrder(timing.paint_timing->first_paint, |
264 timing.paint_timing.first_contentful_paint)) { | 264 timing.paint_timing->first_contentful_paint)) { |
265 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 265 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint |
266 << " for first_contentful_paint " | 266 << " for first_contentful_paint " |
267 << timing.paint_timing.first_contentful_paint; | 267 << timing.paint_timing->first_contentful_paint; |
268 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_CONTENTFUL_PAINT; | 268 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_CONTENTFUL_PAINT; |
269 } | 269 } |
270 | 270 |
271 if (!EventsInOrder(timing.paint_timing.first_paint, | 271 if (!EventsInOrder(timing.paint_timing->first_paint, |
272 timing.paint_timing.first_meaningful_paint)) { | 272 timing.paint_timing->first_meaningful_paint)) { |
273 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 273 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint |
274 << " for first_meaningful_paint " | 274 << " for first_meaningful_paint " |
275 << timing.paint_timing.first_meaningful_paint; | 275 << timing.paint_timing->first_meaningful_paint; |
276 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; | 276 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; |
277 } | 277 } |
278 | 278 |
279 return internal::VALID; | 279 return internal::VALID; |
280 } | 280 } |
281 | 281 |
282 // Updates *|inout_existing_value| with |optional_candidate_new_value|, if | 282 // Updates *|inout_existing_value| with |optional_candidate_new_value|, if |
283 // either *|inout_existing_value| isn't set, or |optional_candidate_new_value| < | 283 // either *|inout_existing_value| isn't set, or |optional_candidate_new_value| < |
284 // |inout_existing_value|. | 284 // |inout_existing_value|. |
285 void MaybeUpdateTimeDelta( | 285 void MaybeUpdateTimeDelta( |
(...skipping 26 matching lines...) Expand all Loading... |
312 } | 312 } |
313 | 313 |
314 *inout_existing_value = candidate_new_value; | 314 *inout_existing_value = candidate_new_value; |
315 } | 315 } |
316 | 316 |
317 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { | 317 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { |
318 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, | 318 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, |
319 completed_after_background); | 319 completed_after_background); |
320 } | 320 } |
321 | 321 |
322 void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer, | 322 void DispatchObserverTimingCallbacks( |
323 const PageLoadTiming& last_timing, | 323 PageLoadMetricsObserver* observer, |
324 const PageLoadTiming& new_timing, | 324 const mojom::PageLoadTiming& last_timing, |
325 const PageLoadMetadata& last_metadata, | 325 const mojom::PageLoadTiming& new_timing, |
326 const PageLoadExtraInfo& extra_info) { | 326 const mojom::PageLoadMetadata& last_metadata, |
| 327 const PageLoadExtraInfo& extra_info) { |
327 if (extra_info.main_frame_metadata.behavior_flags != | 328 if (extra_info.main_frame_metadata.behavior_flags != |
328 last_metadata.behavior_flags) | 329 last_metadata.behavior_flags) |
329 observer->OnLoadingBehaviorObserved(extra_info); | 330 observer->OnLoadingBehaviorObserved(extra_info); |
330 if (last_timing != new_timing) | 331 if (!last_timing.Equals(new_timing)) |
331 observer->OnTimingUpdate(new_timing, extra_info); | 332 observer->OnTimingUpdate(new_timing, extra_info); |
332 if (new_timing.document_timing.dom_content_loaded_event_start && | 333 if (new_timing.document_timing->dom_content_loaded_event_start && |
333 !last_timing.document_timing.dom_content_loaded_event_start) | 334 !last_timing.document_timing->dom_content_loaded_event_start) |
334 observer->OnDomContentLoadedEventStart(new_timing, extra_info); | 335 observer->OnDomContentLoadedEventStart(new_timing, extra_info); |
335 if (new_timing.document_timing.load_event_start && | 336 if (new_timing.document_timing->load_event_start && |
336 !last_timing.document_timing.load_event_start) | 337 !last_timing.document_timing->load_event_start) |
337 observer->OnLoadEventStart(new_timing, extra_info); | 338 observer->OnLoadEventStart(new_timing, extra_info); |
338 if (new_timing.document_timing.first_layout && | 339 if (new_timing.document_timing->first_layout && |
339 !last_timing.document_timing.first_layout) | 340 !last_timing.document_timing->first_layout) |
340 observer->OnFirstLayout(new_timing, extra_info); | 341 observer->OnFirstLayout(new_timing, extra_info); |
341 if (new_timing.paint_timing.first_paint && | 342 if (new_timing.paint_timing->first_paint && |
342 !last_timing.paint_timing.first_paint) | 343 !last_timing.paint_timing->first_paint) |
343 observer->OnFirstPaintInPage(new_timing, extra_info); | 344 observer->OnFirstPaintInPage(new_timing, extra_info); |
344 if (new_timing.paint_timing.first_text_paint && | 345 if (new_timing.paint_timing->first_text_paint && |
345 !last_timing.paint_timing.first_text_paint) | 346 !last_timing.paint_timing->first_text_paint) |
346 observer->OnFirstTextPaintInPage(new_timing, extra_info); | 347 observer->OnFirstTextPaintInPage(new_timing, extra_info); |
347 if (new_timing.paint_timing.first_image_paint && | 348 if (new_timing.paint_timing->first_image_paint && |
348 !last_timing.paint_timing.first_image_paint) | 349 !last_timing.paint_timing->first_image_paint) |
349 observer->OnFirstImagePaintInPage(new_timing, extra_info); | 350 observer->OnFirstImagePaintInPage(new_timing, extra_info); |
350 if (new_timing.paint_timing.first_contentful_paint && | 351 if (new_timing.paint_timing->first_contentful_paint && |
351 !last_timing.paint_timing.first_contentful_paint) | 352 !last_timing.paint_timing->first_contentful_paint) |
352 observer->OnFirstContentfulPaintInPage(new_timing, extra_info); | 353 observer->OnFirstContentfulPaintInPage(new_timing, extra_info); |
353 if (new_timing.paint_timing.first_meaningful_paint && | 354 if (new_timing.paint_timing->first_meaningful_paint && |
354 !last_timing.paint_timing.first_meaningful_paint) | 355 !last_timing.paint_timing->first_meaningful_paint) |
355 observer->OnFirstMeaningfulPaintInMainFrameDocument(new_timing, extra_info); | 356 observer->OnFirstMeaningfulPaintInMainFrameDocument(new_timing, extra_info); |
356 if (new_timing.parse_timing.parse_start && | 357 if (new_timing.parse_timing->parse_start && |
357 !last_timing.parse_timing.parse_start) | 358 !last_timing.parse_timing->parse_start) |
358 observer->OnParseStart(new_timing, extra_info); | 359 observer->OnParseStart(new_timing, extra_info); |
359 if (new_timing.parse_timing.parse_stop && | 360 if (new_timing.parse_timing->parse_stop && |
360 !last_timing.parse_timing.parse_stop) | 361 !last_timing.parse_timing->parse_stop) |
361 observer->OnParseStop(new_timing, extra_info); | 362 observer->OnParseStop(new_timing, extra_info); |
362 } | 363 } |
363 | 364 |
364 } // namespace | 365 } // namespace |
365 | 366 |
366 PageLoadTracker::PageLoadTracker( | 367 PageLoadTracker::PageLoadTracker( |
367 bool in_foreground, | 368 bool in_foreground, |
368 PageLoadMetricsEmbedderInterface* embedder_interface, | 369 PageLoadMetricsEmbedderInterface* embedder_interface, |
369 const GURL& currently_committed_url, | 370 const GURL& currently_committed_url, |
370 content::NavigationHandle* navigation_handle, | 371 content::NavigationHandle* navigation_handle, |
371 UserInitiatedInfo user_initiated_info, | 372 UserInitiatedInfo user_initiated_info, |
372 int aborted_chain_size, | 373 int aborted_chain_size, |
373 int aborted_chain_size_same_url) | 374 int aborted_chain_size_same_url) |
374 : did_stop_tracking_(false), | 375 : did_stop_tracking_(false), |
375 app_entered_background_(false), | 376 app_entered_background_(false), |
376 navigation_start_(navigation_handle->NavigationStart()), | 377 navigation_start_(navigation_handle->NavigationStart()), |
377 url_(navigation_handle->GetURL()), | 378 url_(navigation_handle->GetURL()), |
378 start_url_(navigation_handle->GetURL()), | 379 start_url_(navigation_handle->GetURL()), |
379 did_commit_(false), | 380 did_commit_(false), |
380 page_end_reason_(END_NONE), | 381 page_end_reason_(END_NONE), |
381 page_end_user_initiated_info_(UserInitiatedInfo::NotUserInitiated()), | 382 page_end_user_initiated_info_(UserInitiatedInfo::NotUserInitiated()), |
382 started_in_foreground_(in_foreground), | 383 started_in_foreground_(in_foreground), |
| 384 merged_page_timing_(CreatePageLoadTiming()), |
383 page_transition_(navigation_handle->GetPageTransition()), | 385 page_transition_(navigation_handle->GetPageTransition()), |
384 user_initiated_info_(user_initiated_info), | 386 user_initiated_info_(user_initiated_info), |
385 aborted_chain_size_(aborted_chain_size), | 387 aborted_chain_size_(aborted_chain_size), |
386 aborted_chain_size_same_url_(aborted_chain_size_same_url), | 388 aborted_chain_size_same_url_(aborted_chain_size_same_url), |
387 embedder_interface_(embedder_interface) { | 389 embedder_interface_(embedder_interface) { |
388 DCHECK(!navigation_handle->HasCommitted()); | 390 DCHECK(!navigation_handle->HasCommitted()); |
389 embedder_interface_->RegisterObservers(this); | 391 embedder_interface_->RegisterObservers(this); |
390 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnStart, navigation_handle, | 392 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnStart, navigation_handle, |
391 currently_committed_url, started_in_foreground_); | 393 currently_committed_url, started_in_foreground_); |
392 | 394 |
(...skipping 27 matching lines...) Expand all Loading... |
420 if (!failed_provisional_load_info_) | 422 if (!failed_provisional_load_info_) |
421 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); | 423 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); |
422 | 424 |
423 // Don't include any aborts that resulted in a new navigation, as the chain | 425 // Don't include any aborts that resulted in a new navigation, as the chain |
424 // length will be included in the aborter PageLoadTracker. | 426 // length will be included in the aborter PageLoadTracker. |
425 if (page_end_reason_ != END_RELOAD && | 427 if (page_end_reason_ != END_RELOAD && |
426 page_end_reason_ != END_FORWARD_BACK && | 428 page_end_reason_ != END_FORWARD_BACK && |
427 page_end_reason_ != END_NEW_NAVIGATION) { | 429 page_end_reason_ != END_NEW_NAVIGATION) { |
428 LogAbortChainHistograms(nullptr); | 430 LogAbortChainHistograms(nullptr); |
429 } | 431 } |
430 } else if (merged_page_timing_.IsEmpty()) { | 432 } else if (page_load_metrics::IsEmpty(*merged_page_timing_)) { |
431 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 433 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
432 } | 434 } |
433 | 435 |
434 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 436 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
435 for (const auto& observer : observers_) { | 437 for (const auto& observer : observers_) { |
436 if (failed_provisional_load_info_) { | 438 if (failed_provisional_load_info_) { |
437 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); | 439 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); |
438 } else if (did_commit_) { | 440 } else if (did_commit_) { |
439 observer->OnComplete(merged_page_timing_, info); | 441 observer->OnComplete(*merged_page_timing_, info); |
440 } | 442 } |
441 } | 443 } |
442 } | 444 } |
443 | 445 |
444 void PageLoadTracker::LogAbortChainHistograms( | 446 void PageLoadTracker::LogAbortChainHistograms( |
445 content::NavigationHandle* final_navigation) { | 447 content::NavigationHandle* final_navigation) { |
446 if (aborted_chain_size_ == 0) | 448 if (aborted_chain_size_ == 0) |
447 return; | 449 return; |
448 // Note that this could be broken out by this navigation's abort type, if more | 450 // Note that this could be broken out by this navigation's abort type, if more |
449 // granularity is needed. Add one to the chain size to count the current | 451 // granularity is needed. Add one to the chain size to count the current |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 // Only log the first time we background in a given page load. | 498 // Only log the first time we background in a given page load. |
497 if (background_time_.is_null()) { | 499 if (background_time_.is_null()) { |
498 // Make sure we either started in the foreground and haven't been | 500 // Make sure we either started in the foreground and haven't been |
499 // foregrounded yet, or started in the background and have already been | 501 // foregrounded yet, or started in the background and have already been |
500 // foregrounded. | 502 // foregrounded. |
501 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); | 503 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); |
502 background_time_ = base::TimeTicks::Now(); | 504 background_time_ = base::TimeTicks::Now(); |
503 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); | 505 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); |
504 } | 506 } |
505 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 507 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
506 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, merged_page_timing_, info); | 508 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, *merged_page_timing_, info); |
507 } | 509 } |
508 | 510 |
509 void PageLoadTracker::WebContentsShown() { | 511 void PageLoadTracker::WebContentsShown() { |
510 // Only log the first time we foreground in a given page load. | 512 // Only log the first time we foreground in a given page load. |
511 if (foreground_time_.is_null()) { | 513 if (foreground_time_.is_null()) { |
512 // Make sure we either started in the background and haven't been | 514 // Make sure we either started in the background and haven't been |
513 // backgrounded yet, or started in the foreground and have already been | 515 // backgrounded yet, or started in the foreground and have already been |
514 // backgrounded. | 516 // backgrounded. |
515 DCHECK_NE(started_in_foreground_, background_time_.is_null()); | 517 DCHECK_NE(started_in_foreground_, background_time_.is_null()); |
516 foreground_time_ = base::TimeTicks::Now(); | 518 foreground_time_ = base::TimeTicks::Now(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
602 } | 604 } |
603 | 605 |
604 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { | 606 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { |
605 if (!app_entered_background_) { | 607 if (!app_entered_background_) { |
606 RecordAppBackgroundPageLoadCompleted(false); | 608 RecordAppBackgroundPageLoadCompleted(false); |
607 app_entered_background_ = true; | 609 app_entered_background_ = true; |
608 } | 610 } |
609 | 611 |
610 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 612 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
611 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground, | 613 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground, |
612 merged_page_timing_, info); | 614 *merged_page_timing_, info); |
613 } | 615 } |
614 | 616 |
615 void PageLoadTracker::NotifyClientRedirectTo( | 617 void PageLoadTracker::NotifyClientRedirectTo( |
616 const PageLoadTracker& destination) { | 618 const PageLoadTracker& destination) { |
617 if (merged_page_timing_.paint_timing.first_paint) { | 619 if (merged_page_timing_->paint_timing->first_paint) { |
618 base::TimeTicks first_paint_time = | 620 base::TimeTicks first_paint_time = |
619 navigation_start() + | 621 navigation_start() + |
620 merged_page_timing_.paint_timing.first_paint.value(); | 622 merged_page_timing_->paint_timing->first_paint.value(); |
621 base::TimeDelta first_paint_to_navigation; | 623 base::TimeDelta first_paint_to_navigation; |
622 if (destination.navigation_start() > first_paint_time) | 624 if (destination.navigation_start() > first_paint_time) |
623 first_paint_to_navigation = | 625 first_paint_to_navigation = |
624 destination.navigation_start() - first_paint_time; | 626 destination.navigation_start() - first_paint_time; |
625 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation, | 627 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation, |
626 first_paint_to_navigation); | 628 first_paint_to_navigation); |
627 } else { | 629 } else { |
628 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true); | 630 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true); |
629 } | 631 } |
630 } | 632 } |
631 | 633 |
632 void PageLoadTracker::UpdateSubFrameTiming( | 634 void PageLoadTracker::UpdateSubFrameTiming( |
633 content::RenderFrameHost* render_frame_host, | 635 content::RenderFrameHost* render_frame_host, |
634 const PageLoadTiming& new_timing, | 636 const mojom::PageLoadTiming& new_timing, |
635 const PageLoadMetadata& new_metadata) { | 637 const mojom::PageLoadMetadata& new_metadata) { |
636 UpdateSubFrameMetadata(new_metadata); | 638 UpdateSubFrameMetadata(new_metadata); |
637 const auto it = subframe_navigation_start_offset_.find( | 639 const auto it = subframe_navigation_start_offset_.find( |
638 render_frame_host->GetFrameTreeNodeId()); | 640 render_frame_host->GetFrameTreeNodeId()); |
639 if (it == subframe_navigation_start_offset_.end()) { | 641 if (it == subframe_navigation_start_offset_.end()) { |
640 // We received timing information for an untracked load. Ignore it. | 642 // We received timing information for an untracked load. Ignore it. |
641 return; | 643 return; |
642 } | 644 } |
643 | 645 |
644 base::TimeDelta navigation_start_offset = it->second; | 646 base::TimeDelta navigation_start_offset = it->second; |
645 const PageLoadTiming last_timing = merged_page_timing_; | 647 const mojom::PageLoadTimingPtr last_timing = merged_page_timing_->Clone(); |
646 MergePaintTiming(navigation_start_offset, new_timing.paint_timing, | 648 MergePaintTiming(navigation_start_offset, *(new_timing.paint_timing), |
647 false /* is_main_frame */); | 649 false /* is_main_frame */); |
648 | 650 |
649 if (last_timing == merged_page_timing_) | 651 if (last_timing->Equals(*merged_page_timing_)) |
650 return; | 652 return; |
651 | 653 |
652 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 654 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
653 for (const auto& observer : observers_) { | 655 for (const auto& observer : observers_) { |
654 DispatchObserverTimingCallbacks(observer.get(), last_timing, | 656 DispatchObserverTimingCallbacks(observer.get(), *last_timing, |
655 merged_page_timing_, main_frame_metadata_, | 657 *merged_page_timing_, main_frame_metadata_, |
656 info); | 658 info); |
657 } | 659 } |
658 } | 660 } |
659 | 661 |
660 void PageLoadTracker::MergePaintTiming( | 662 void PageLoadTracker::MergePaintTiming( |
661 base::TimeDelta navigation_start_offset, | 663 base::TimeDelta navigation_start_offset, |
662 const page_load_metrics::PaintTiming& new_paint_timing, | 664 const mojom::PaintTiming& new_paint_timing, |
663 bool is_main_frame) { | 665 bool is_main_frame) { |
664 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_paint, | 666 MaybeUpdateTimeDelta(&merged_page_timing_->paint_timing->first_paint, |
665 navigation_start_offset, new_paint_timing.first_paint); | 667 navigation_start_offset, new_paint_timing.first_paint); |
666 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_text_paint, | 668 MaybeUpdateTimeDelta(&merged_page_timing_->paint_timing->first_text_paint, |
667 navigation_start_offset, | 669 navigation_start_offset, |
668 new_paint_timing.first_text_paint); | 670 new_paint_timing.first_text_paint); |
669 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_image_paint, | 671 MaybeUpdateTimeDelta(&merged_page_timing_->paint_timing->first_image_paint, |
670 navigation_start_offset, | 672 navigation_start_offset, |
671 new_paint_timing.first_image_paint); | 673 new_paint_timing.first_image_paint); |
672 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_contentful_paint, | 674 MaybeUpdateTimeDelta( |
673 navigation_start_offset, | 675 &merged_page_timing_->paint_timing->first_contentful_paint, |
674 new_paint_timing.first_contentful_paint); | 676 navigation_start_offset, new_paint_timing.first_contentful_paint); |
675 if (is_main_frame) { | 677 if (is_main_frame) { |
676 // first meaningful paint is only tracked in the main frame. | 678 // first meaningful paint is only tracked in the main frame. |
677 merged_page_timing_.paint_timing.first_meaningful_paint = | 679 merged_page_timing_->paint_timing->first_meaningful_paint = |
678 new_paint_timing.first_meaningful_paint; | 680 new_paint_timing.first_meaningful_paint; |
679 } | 681 } |
680 } | 682 } |
681 | 683 |
682 void PageLoadTracker::UpdateSubFrameMetadata( | 684 void PageLoadTracker::UpdateSubFrameMetadata( |
683 const PageLoadMetadata& subframe_metadata) { | 685 const mojom::PageLoadMetadata& subframe_metadata) { |
684 // Merge the subframe loading behavior flags with any we've already observed, | 686 // Merge the subframe loading behavior flags with any we've already observed, |
685 // possibly from other subframes. | 687 // possibly from other subframes. |
686 const int last_subframe_loading_behavior_flags = | 688 const int last_subframe_loading_behavior_flags = |
687 subframe_metadata_.behavior_flags; | 689 subframe_metadata_.behavior_flags; |
688 subframe_metadata_.behavior_flags |= subframe_metadata.behavior_flags; | 690 subframe_metadata_.behavior_flags |= subframe_metadata.behavior_flags; |
689 if (last_subframe_loading_behavior_flags == subframe_metadata_.behavior_flags) | 691 if (last_subframe_loading_behavior_flags == subframe_metadata_.behavior_flags) |
690 return; | 692 return; |
691 | 693 |
692 PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo()); | 694 PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo()); |
693 for (const auto& observer : observers_) { | 695 for (const auto& observer : observers_) { |
694 observer->OnLoadingBehaviorObserved(extra_info); | 696 observer->OnLoadingBehaviorObserved(extra_info); |
695 } | 697 } |
696 } | 698 } |
697 | 699 |
698 void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, | 700 void PageLoadTracker::UpdateTiming( |
699 const PageLoadMetadata& new_metadata) { | 701 const mojom::PageLoadTiming& new_timing, |
| 702 const mojom::PageLoadMetadata& new_metadata) { |
700 // Throw away IPCs that are not relevant to the current navigation. | 703 // Throw away IPCs that are not relevant to the current navigation. |
701 // Two timing structures cannot refer to the same navigation if they indicate | 704 // Two timing structures cannot refer to the same navigation if they indicate |
702 // that a navigation started at different times, so a new timing struct with a | 705 // that a navigation started at different times, so a new timing struct with a |
703 // different start time from an earlier struct is considered invalid. | 706 // different start time from an earlier struct is considered invalid. |
704 const bool valid_timing_descendent = | 707 const bool valid_timing_descendent = |
705 merged_page_timing_.navigation_start.is_null() || | 708 merged_page_timing_->navigation_start.is_null() || |
706 merged_page_timing_.navigation_start == new_timing.navigation_start; | 709 merged_page_timing_->navigation_start == new_timing.navigation_start; |
707 if (!valid_timing_descendent) { | 710 if (!valid_timing_descendent) { |
708 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT); | 711 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT); |
709 return; | 712 return; |
710 } | 713 } |
711 | 714 |
712 // Ensure flags sent previously are still present in the new metadata fields. | 715 // Ensure flags sent previously are still present in the new metadata fields. |
713 const bool valid_behavior_descendent = | 716 const bool valid_behavior_descendent = |
714 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) == | 717 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) == |
715 main_frame_metadata_.behavior_flags; | 718 main_frame_metadata_.behavior_flags; |
716 if (!valid_behavior_descendent) { | 719 if (!valid_behavior_descendent) { |
717 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); | 720 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); |
718 return; | 721 return; |
719 } | 722 } |
720 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing); | 723 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing); |
721 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status, | 724 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status, |
722 internal::LAST_PAGE_LOAD_TIMING_STATUS); | 725 internal::LAST_PAGE_LOAD_TIMING_STATUS); |
723 if (status != internal::VALID) { | 726 if (status != internal::VALID) { |
724 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); | 727 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); |
725 return; | 728 return; |
726 } | 729 } |
727 | 730 |
728 DCHECK(did_commit_); // OnCommit() must be called first. | 731 DCHECK(did_commit_); // OnCommit() must be called first. |
729 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() | 732 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() |
730 // must be called before DispatchObserverTimingCallbacks, but its | 733 // must be called before DispatchObserverTimingCallbacks, but its |
731 // implementation depends on the state of main_frame_metadata_, so we need | 734 // implementation depends on the state of main_frame_metadata_, so we need |
732 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. | 735 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. |
733 // Thus, we make a copy of timing here, update timing_ and | 736 // Thus, we make a copy of timing here, update merged_page_timing_ and |
734 // main_frame_metadata_, and then proceed to dispatch the observer timing | 737 // main_frame_metadata_, and then proceed to dispatch the observer timing |
735 // callbacks. | 738 // callbacks. |
736 const PageLoadTiming last_timing = merged_page_timing_; | 739 const mojom::PageLoadTimingPtr last_timing = std::move(merged_page_timing_); |
737 | 740 |
738 // Update the merged_page_timing_, making sure to merge the previously | 741 // Update the merged_page_timing_, making sure to merge the previously |
739 // observed |paint_timing|, which is tracked across all frames in the page. | 742 // observed |paint_timing|, which is tracked across all frames in the page. |
740 merged_page_timing_ = new_timing; | 743 merged_page_timing_ = new_timing.Clone(); |
741 merged_page_timing_.paint_timing = last_timing.paint_timing; | 744 merged_page_timing_->paint_timing = last_timing->paint_timing->Clone(); |
742 MergePaintTiming(base::TimeDelta(), new_timing.paint_timing, | 745 MergePaintTiming(base::TimeDelta(), *(new_timing.paint_timing), |
743 true /* is_main_frame */); | 746 true /* is_main_frame */); |
744 | 747 |
745 const PageLoadMetadata last_metadata = main_frame_metadata_; | 748 const mojom::PageLoadMetadataPtr last_metadata = main_frame_metadata_.Clone(); |
746 main_frame_metadata_ = new_metadata; | 749 main_frame_metadata_ = new_metadata; |
747 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 750 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
748 for (const auto& observer : observers_) { | 751 for (const auto& observer : observers_) { |
749 DispatchObserverTimingCallbacks(observer.get(), last_timing, | 752 DispatchObserverTimingCallbacks(observer.get(), *last_timing, |
750 merged_page_timing_, last_metadata, info); | 753 *merged_page_timing_, *last_metadata, info); |
751 } | 754 } |
752 } | 755 } |
753 | 756 |
754 void PageLoadTracker::OnStartedResource( | 757 void PageLoadTracker::OnStartedResource( |
755 const ExtraRequestStartInfo& extra_request_start_info) { | 758 const ExtraRequestStartInfo& extra_request_start_info) { |
756 for (const auto& observer : observers_) { | 759 for (const auto& observer : observers_) { |
757 observer->OnStartedResource(extra_request_start_info); | 760 observer->OnStartedResource(extra_request_start_info); |
758 } | 761 } |
759 } | 762 } |
760 | 763 |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
936 observer->MediaStartedPlaying(video_type, is_in_main_frame); | 939 observer->MediaStartedPlaying(video_type, is_in_main_frame); |
937 } | 940 } |
938 | 941 |
939 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, | 942 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, |
940 base::TimeDelta actual_delay) { | 943 base::TimeDelta actual_delay) { |
941 for (const auto& observer : observers_) | 944 for (const auto& observer : observers_) |
942 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); | 945 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); |
943 } | 946 } |
944 | 947 |
945 } // namespace page_load_metrics | 948 } // namespace page_load_metrics |
OLD | NEW |