| 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 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 bool EventsInOrder(const base::Optional<base::TimeDelta>& first, | 122 bool EventsInOrder(const base::Optional<base::TimeDelta>& first, |
| 123 const base::Optional<base::TimeDelta>& second) { | 123 const base::Optional<base::TimeDelta>& second) { |
| 124 if (!second) { | 124 if (!second) { |
| 125 return true; | 125 return true; |
| 126 } | 126 } |
| 127 return first && first <= second; | 127 return first && first <= second; |
| 128 } | 128 } |
| 129 | 129 |
| 130 internal::PageLoadTimingStatus IsValidPageLoadTiming( | 130 internal::PageLoadTimingStatus IsValidPageLoadTiming( |
| 131 const PageLoadTiming& timing) { | 131 const PageLoadTiming& timing) { |
| 132 if (timing.IsEmpty()) | 132 if (page_load_metrics::IsEmpty(timing)) |
| 133 return internal::INVALID_EMPTY_TIMING; | 133 return internal::INVALID_EMPTY_TIMING; |
| 134 | 134 |
| 135 // If we have a non-empty timing, it should always have a navigation start. | 135 // If we have a non-empty timing, it should always have a navigation start. |
| 136 if (timing.navigation_start.is_null()) { | 136 if (timing.navigation_start.is_null()) { |
| 137 LOG(ERROR) << "Received null navigation_start."; | 137 LOG(ERROR) << "Received null navigation_start."; |
| 138 return internal::INVALID_NULL_NAVIGATION_START; | 138 return internal::INVALID_NULL_NAVIGATION_START; |
| 139 } | 139 } |
| 140 | 140 |
| 141 // Verify proper ordering between the various timings. | 141 // Verify proper ordering between the various timings. |
| 142 | 142 |
| 143 if (!EventsInOrder(timing.response_start, timing.parse_timing.parse_start)) { | 143 if (!EventsInOrder(timing.response_start, timing.parse_timing->parse_start)) { |
| 144 // We sometimes get a zero response_start with a non-zero parse start. See | 144 // We sometimes get a zero response_start with a non-zero parse start. See |
| 145 // crbug.com/590212. | 145 // crbug.com/590212. |
| 146 LOG(ERROR) << "Invalid response_start " << timing.response_start | 146 LOG(ERROR) << "Invalid response_start " << timing.response_start |
| 147 << " for parse_start " << timing.parse_timing.parse_start; | 147 << " for parse_start " << timing.parse_timing->parse_start; |
| 148 // When browser-side navigation is enabled, we sometimes encounter this | 148 // When browser-side navigation is enabled, we sometimes encounter this |
| 149 // error case. For now, we disable reporting of this error, since most | 149 // error case. For now, we disable reporting of this error, since most |
| 150 // PageLoadMetricsObservers don't care about response_start and we want to | 150 // PageLoadMetricsObservers don't care about response_start and we want to |
| 151 // see how much closer fixing this error will get us to page load metrics | 151 // see how much closer fixing this error will get us to page load metrics |
| 152 // being consistent with and without browser side navigation enabled. See | 152 // being consistent with and without browser side navigation enabled. See |
| 153 // crbug.com/716587 for more details. | 153 // crbug.com/716587 for more details. |
| 154 // | 154 // |
| 155 // return internal::INVALID_ORDER_RESPONSE_START_PARSE_START; | 155 // return internal::INVALID_ORDER_RESPONSE_START_PARSE_START; |
| 156 } | 156 } |
| 157 | 157 |
| 158 if (!EventsInOrder(timing.parse_timing.parse_start, | 158 if (!EventsInOrder(timing.parse_timing->parse_start, |
| 159 timing.parse_timing.parse_stop)) { | 159 timing.parse_timing->parse_stop)) { |
| 160 LOG(ERROR) << "Invalid parse_start " << timing.parse_timing.parse_start | 160 LOG(ERROR) << "Invalid parse_start " << timing.parse_timing->parse_start |
| 161 << " for parse_stop " << timing.parse_timing.parse_stop; | 161 << " for parse_stop " << timing.parse_timing->parse_stop; |
| 162 return internal::INVALID_ORDER_PARSE_START_PARSE_STOP; | 162 return internal::INVALID_ORDER_PARSE_START_PARSE_STOP; |
| 163 } | 163 } |
| 164 | 164 |
| 165 if (timing.parse_timing.parse_stop) { | 165 if (timing.parse_timing->parse_stop) { |
| 166 const base::TimeDelta parse_duration = | 166 const base::TimeDelta parse_duration = |
| 167 timing.parse_timing.parse_stop.value() - | 167 timing.parse_timing->parse_stop.value() - |
| 168 timing.parse_timing.parse_start.value(); | 168 timing.parse_timing->parse_start.value(); |
| 169 if (timing.parse_timing.parse_blocked_on_script_load_duration > | 169 if (timing.parse_timing->parse_blocked_on_script_load_duration > |
| 170 parse_duration) { | 170 parse_duration) { |
| 171 LOG(ERROR) << "Invalid parse_blocked_on_script_load_duration " | 171 LOG(ERROR) << "Invalid parse_blocked_on_script_load_duration " |
| 172 << timing.parse_timing.parse_blocked_on_script_load_duration | 172 << timing.parse_timing->parse_blocked_on_script_load_duration |
| 173 << " for parse duration " << parse_duration; | 173 << " for parse duration " << parse_duration; |
| 174 return internal::INVALID_SCRIPT_LOAD_LONGER_THAN_PARSE; | 174 return internal::INVALID_SCRIPT_LOAD_LONGER_THAN_PARSE; |
| 175 } | 175 } |
| 176 if (timing.parse_timing.parse_blocked_on_script_execution_duration > | 176 if (timing.parse_timing->parse_blocked_on_script_execution_duration > |
| 177 parse_duration) { | 177 parse_duration) { |
| 178 LOG(ERROR) | 178 LOG(ERROR) |
| 179 << "Invalid parse_blocked_on_script_execution_duration " | 179 << "Invalid parse_blocked_on_script_execution_duration " |
| 180 << timing.parse_timing.parse_blocked_on_script_execution_duration | 180 << timing.parse_timing->parse_blocked_on_script_execution_duration |
| 181 << " for parse duration " << parse_duration; | 181 << " for parse duration " << parse_duration; |
| 182 return internal::INVALID_SCRIPT_EXEC_LONGER_THAN_PARSE; | 182 return internal::INVALID_SCRIPT_EXEC_LONGER_THAN_PARSE; |
| 183 } | 183 } |
| 184 } | 184 } |
| 185 | 185 |
| 186 if (timing.parse_timing | 186 if (timing.parse_timing |
| 187 .parse_blocked_on_script_load_from_document_write_duration > | 187 ->parse_blocked_on_script_load_from_document_write_duration > |
| 188 timing.parse_timing.parse_blocked_on_script_load_duration) { | 188 timing.parse_timing->parse_blocked_on_script_load_duration) { |
| 189 LOG(ERROR) | 189 LOG(ERROR) |
| 190 << "Invalid parse_blocked_on_script_load_from_document_write_duration " | 190 << "Invalid parse_blocked_on_script_load_from_document_write_duration " |
| 191 << timing.parse_timing | 191 << timing.parse_timing |
| 192 .parse_blocked_on_script_load_from_document_write_duration | 192 ->parse_blocked_on_script_load_from_document_write_duration |
| 193 << " for parse_blocked_on_script_load_duration " | 193 << " for parse_blocked_on_script_load_duration " |
| 194 << timing.parse_timing.parse_blocked_on_script_load_duration; | 194 << timing.parse_timing->parse_blocked_on_script_load_duration; |
| 195 return internal::INVALID_SCRIPT_LOAD_DOC_WRITE_LONGER_THAN_SCRIPT_LOAD; | 195 return internal::INVALID_SCRIPT_LOAD_DOC_WRITE_LONGER_THAN_SCRIPT_LOAD; |
| 196 } | 196 } |
| 197 | 197 |
| 198 if (timing.parse_timing | 198 if (timing.parse_timing |
| 199 .parse_blocked_on_script_execution_from_document_write_duration > | 199 ->parse_blocked_on_script_execution_from_document_write_duration > |
| 200 timing.parse_timing.parse_blocked_on_script_execution_duration) { | 200 timing.parse_timing->parse_blocked_on_script_execution_duration) { |
| 201 LOG(ERROR) | 201 LOG(ERROR) |
| 202 << "Invalid " | 202 << "Invalid " |
| 203 "parse_blocked_on_script_execution_from_document_write_duration " | 203 "parse_blocked_on_script_execution_from_document_write_duration " |
| 204 << timing.parse_timing | 204 << timing.parse_timing |
| 205 .parse_blocked_on_script_execution_from_document_write_duration | 205 ->parse_blocked_on_script_execution_from_document_write_duration |
| 206 << " for parse_blocked_on_script_execution_duration " | 206 << " for parse_blocked_on_script_execution_duration " |
| 207 << timing.parse_timing.parse_blocked_on_script_execution_duration; | 207 << timing.parse_timing->parse_blocked_on_script_execution_duration; |
| 208 return internal::INVALID_SCRIPT_EXEC_DOC_WRITE_LONGER_THAN_SCRIPT_EXEC; | 208 return internal::INVALID_SCRIPT_EXEC_DOC_WRITE_LONGER_THAN_SCRIPT_EXEC; |
| 209 } | 209 } |
| 210 | 210 |
| 211 if (!EventsInOrder(timing.parse_timing.parse_stop, | 211 if (!EventsInOrder(timing.parse_timing->parse_stop, |
| 212 timing.document_timing.dom_content_loaded_event_start)) { | 212 timing.document_timing->dom_content_loaded_event_start)) { |
| 213 LOG(ERROR) << "Invalid parse_stop " << timing.parse_timing.parse_stop | 213 LOG(ERROR) << "Invalid parse_stop " << timing.parse_timing->parse_stop |
| 214 << " for dom_content_loaded_event_start " | 214 << " for dom_content_loaded_event_start " |
| 215 << timing.document_timing.dom_content_loaded_event_start; | 215 << timing.document_timing->dom_content_loaded_event_start; |
| 216 return internal::INVALID_ORDER_PARSE_STOP_DOM_CONTENT_LOADED; | 216 return internal::INVALID_ORDER_PARSE_STOP_DOM_CONTENT_LOADED; |
| 217 } | 217 } |
| 218 | 218 |
| 219 if (!EventsInOrder(timing.document_timing.dom_content_loaded_event_start, | 219 if (!EventsInOrder(timing.document_timing->dom_content_loaded_event_start, |
| 220 timing.document_timing.load_event_start)) { | 220 timing.document_timing->load_event_start)) { |
| 221 LOG(ERROR) << "Invalid dom_content_loaded_event_start " | 221 LOG(ERROR) << "Invalid dom_content_loaded_event_start " |
| 222 << timing.document_timing.dom_content_loaded_event_start | 222 << timing.document_timing->dom_content_loaded_event_start |
| 223 << " for load_event_start " | 223 << " for load_event_start " |
| 224 << timing.document_timing.load_event_start; | 224 << timing.document_timing->load_event_start; |
| 225 return internal::INVALID_ORDER_DOM_CONTENT_LOADED_LOAD; | 225 return internal::INVALID_ORDER_DOM_CONTENT_LOADED_LOAD; |
| 226 } | 226 } |
| 227 | 227 |
| 228 if (!EventsInOrder(timing.parse_timing.parse_start, | 228 if (!EventsInOrder(timing.parse_timing->parse_start, |
| 229 timing.document_timing.first_layout)) { | 229 timing.document_timing->first_layout)) { |
| 230 LOG(ERROR) << "Invalid parse_start " << timing.parse_timing.parse_start | 230 LOG(ERROR) << "Invalid parse_start " << timing.parse_timing->parse_start |
| 231 << " for first_layout " << timing.document_timing.first_layout; | 231 << " for first_layout " << timing.document_timing->first_layout; |
| 232 return internal::INVALID_ORDER_PARSE_START_FIRST_LAYOUT; | 232 return internal::INVALID_ORDER_PARSE_START_FIRST_LAYOUT; |
| 233 } | 233 } |
| 234 | 234 |
| 235 if (!EventsInOrder(timing.document_timing.first_layout, | 235 if (!EventsInOrder(timing.document_timing->first_layout, |
| 236 timing.paint_timing.first_paint)) { | 236 timing.paint_timing->first_paint)) { |
| 237 // This can happen when we process an XHTML document that doesn't contain | 237 // This can happen when we process an XHTML document that doesn't contain |
| 238 // well formed XML. See crbug.com/627607. | 238 // well formed XML. See crbug.com/627607. |
| 239 DLOG(ERROR) << "Invalid first_layout " | 239 DLOG(ERROR) << "Invalid first_layout " |
| 240 << timing.document_timing.first_layout << " for first_paint " | 240 << timing.document_timing->first_layout << " for first_paint " |
| 241 << timing.paint_timing.first_paint; | 241 << timing.paint_timing->first_paint; |
| 242 return internal::INVALID_ORDER_FIRST_LAYOUT_FIRST_PAINT; | 242 return internal::INVALID_ORDER_FIRST_LAYOUT_FIRST_PAINT; |
| 243 } | 243 } |
| 244 | 244 |
| 245 if (!EventsInOrder(timing.paint_timing.first_paint, | 245 if (!EventsInOrder(timing.paint_timing->first_paint, |
| 246 timing.paint_timing.first_text_paint)) { | 246 timing.paint_timing->first_text_paint)) { |
| 247 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 247 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint |
| 248 << " for first_text_paint " | 248 << " for first_text_paint " |
| 249 << timing.paint_timing.first_text_paint; | 249 << timing.paint_timing->first_text_paint; |
| 250 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_TEXT_PAINT; | 250 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_TEXT_PAINT; |
| 251 } | 251 } |
| 252 | 252 |
| 253 if (!EventsInOrder(timing.paint_timing.first_paint, | 253 if (!EventsInOrder(timing.paint_timing->first_paint, |
| 254 timing.paint_timing.first_image_paint)) { | 254 timing.paint_timing->first_image_paint)) { |
| 255 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 255 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint |
| 256 << " for first_image_paint " | 256 << " for first_image_paint " |
| 257 << timing.paint_timing.first_image_paint; | 257 << timing.paint_timing->first_image_paint; |
| 258 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_IMAGE_PAINT; | 258 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_IMAGE_PAINT; |
| 259 } | 259 } |
| 260 | 260 |
| 261 if (!EventsInOrder(timing.paint_timing.first_paint, | 261 if (!EventsInOrder(timing.paint_timing->first_paint, |
| 262 timing.paint_timing.first_contentful_paint)) { | 262 timing.paint_timing->first_contentful_paint)) { |
| 263 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 263 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint |
| 264 << " for first_contentful_paint " | 264 << " for first_contentful_paint " |
| 265 << timing.paint_timing.first_contentful_paint; | 265 << timing.paint_timing->first_contentful_paint; |
| 266 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_CONTENTFUL_PAINT; | 266 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_CONTENTFUL_PAINT; |
| 267 } | 267 } |
| 268 | 268 |
| 269 if (!EventsInOrder(timing.paint_timing.first_paint, | 269 if (!EventsInOrder(timing.paint_timing->first_paint, |
| 270 timing.paint_timing.first_meaningful_paint)) { | 270 timing.paint_timing->first_meaningful_paint)) { |
| 271 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 271 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint |
| 272 << " for first_meaningful_paint " | 272 << " for first_meaningful_paint " |
| 273 << timing.paint_timing.first_meaningful_paint; | 273 << timing.paint_timing->first_meaningful_paint; |
| 274 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; | 274 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; |
| 275 } | 275 } |
| 276 | 276 |
| 277 return internal::VALID; | 277 return internal::VALID; |
| 278 } | 278 } |
| 279 | 279 |
| 280 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { | 280 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { |
| 281 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, | 281 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, |
| 282 completed_after_background); | 282 completed_after_background); |
| 283 } | 283 } |
| 284 | 284 |
| 285 void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer, | 285 void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer, |
| 286 const PageLoadTiming& last_timing, | 286 const PageLoadTiming& last_timing, |
| 287 const PageLoadTiming& new_timing, | 287 const PageLoadTiming& new_timing, |
| 288 const PageLoadMetadata& last_metadata, | 288 const PageLoadMetadata& last_metadata, |
| 289 const PageLoadExtraInfo& extra_info) { | 289 const PageLoadExtraInfo& extra_info) { |
| 290 if (extra_info.main_frame_metadata.behavior_flags != | 290 if (extra_info.main_frame_metadata.behavior_flags != |
| 291 last_metadata.behavior_flags) | 291 last_metadata.behavior_flags) |
| 292 observer->OnLoadingBehaviorObserved(extra_info); | 292 observer->OnLoadingBehaviorObserved(extra_info); |
| 293 if (last_timing != new_timing) | 293 if (!last_timing.Equals(new_timing)) |
| 294 observer->OnTimingUpdate(new_timing, extra_info); | 294 observer->OnTimingUpdate(new_timing, extra_info); |
| 295 if (new_timing.document_timing.dom_content_loaded_event_start && | 295 if (new_timing.document_timing->dom_content_loaded_event_start && |
| 296 !last_timing.document_timing.dom_content_loaded_event_start) | 296 !last_timing.document_timing->dom_content_loaded_event_start) |
| 297 observer->OnDomContentLoadedEventStart(new_timing, extra_info); | 297 observer->OnDomContentLoadedEventStart(new_timing, extra_info); |
| 298 if (new_timing.document_timing.load_event_start && | 298 if (new_timing.document_timing->load_event_start && |
| 299 !last_timing.document_timing.load_event_start) | 299 !last_timing.document_timing->load_event_start) |
| 300 observer->OnLoadEventStart(new_timing, extra_info); | 300 observer->OnLoadEventStart(new_timing, extra_info); |
| 301 if (new_timing.document_timing.first_layout && | 301 if (new_timing.document_timing->first_layout && |
| 302 !last_timing.document_timing.first_layout) | 302 !last_timing.document_timing->first_layout) |
| 303 observer->OnFirstLayout(new_timing, extra_info); | 303 observer->OnFirstLayout(new_timing, extra_info); |
| 304 if (new_timing.paint_timing.first_paint && | 304 if (new_timing.paint_timing->first_paint && |
| 305 !last_timing.paint_timing.first_paint) | 305 !last_timing.paint_timing->first_paint) |
| 306 observer->OnFirstPaint(new_timing, extra_info); | 306 observer->OnFirstPaint(new_timing, extra_info); |
| 307 if (new_timing.paint_timing.first_text_paint && | 307 if (new_timing.paint_timing->first_text_paint && |
| 308 !last_timing.paint_timing.first_text_paint) | 308 !last_timing.paint_timing->first_text_paint) |
| 309 observer->OnFirstTextPaint(new_timing, extra_info); | 309 observer->OnFirstTextPaint(new_timing, extra_info); |
| 310 if (new_timing.paint_timing.first_image_paint && | 310 if (new_timing.paint_timing->first_image_paint && |
| 311 !last_timing.paint_timing.first_image_paint) | 311 !last_timing.paint_timing->first_image_paint) |
| 312 observer->OnFirstImagePaint(new_timing, extra_info); | 312 observer->OnFirstImagePaint(new_timing, extra_info); |
| 313 if (new_timing.paint_timing.first_contentful_paint && | 313 if (new_timing.paint_timing->first_contentful_paint && |
| 314 !last_timing.paint_timing.first_contentful_paint) | 314 !last_timing.paint_timing->first_contentful_paint) |
| 315 observer->OnFirstContentfulPaint(new_timing, extra_info); | 315 observer->OnFirstContentfulPaint(new_timing, extra_info); |
| 316 if (new_timing.paint_timing.first_meaningful_paint && | 316 if (new_timing.paint_timing->first_meaningful_paint && |
| 317 !last_timing.paint_timing.first_meaningful_paint) | 317 !last_timing.paint_timing->first_meaningful_paint) |
| 318 observer->OnFirstMeaningfulPaint(new_timing, extra_info); | 318 observer->OnFirstMeaningfulPaint(new_timing, extra_info); |
| 319 if (new_timing.parse_timing.parse_start && | 319 if (new_timing.parse_timing->parse_start && |
| 320 !last_timing.parse_timing.parse_start) | 320 !last_timing.parse_timing->parse_start) |
| 321 observer->OnParseStart(new_timing, extra_info); | 321 observer->OnParseStart(new_timing, extra_info); |
| 322 if (new_timing.parse_timing.parse_stop && | 322 if (new_timing.parse_timing->parse_stop && |
| 323 !last_timing.parse_timing.parse_stop) | 323 !last_timing.parse_timing->parse_stop) |
| 324 observer->OnParseStop(new_timing, extra_info); | 324 observer->OnParseStop(new_timing, extra_info); |
| 325 } | 325 } |
| 326 | 326 |
| 327 } // namespace | 327 } // namespace |
| 328 | 328 |
| 329 PageLoadTracker::PageLoadTracker( | 329 PageLoadTracker::PageLoadTracker( |
| 330 bool in_foreground, | 330 bool in_foreground, |
| 331 PageLoadMetricsEmbedderInterface* embedder_interface, | 331 PageLoadMetricsEmbedderInterface* embedder_interface, |
| 332 const GURL& currently_committed_url, | 332 const GURL& currently_committed_url, |
| 333 content::NavigationHandle* navigation_handle, | 333 content::NavigationHandle* navigation_handle, |
| 334 UserInitiatedInfo user_initiated_info, | 334 UserInitiatedInfo user_initiated_info, |
| 335 int aborted_chain_size, | 335 int aborted_chain_size, |
| 336 int aborted_chain_size_same_url) | 336 int aborted_chain_size_same_url) |
| 337 : did_stop_tracking_(false), | 337 : did_stop_tracking_(false), |
| 338 app_entered_background_(false), | 338 app_entered_background_(false), |
| 339 navigation_start_(navigation_handle->NavigationStart()), | 339 navigation_start_(navigation_handle->NavigationStart()), |
| 340 url_(navigation_handle->GetURL()), | 340 url_(navigation_handle->GetURL()), |
| 341 start_url_(navigation_handle->GetURL()), | 341 start_url_(navigation_handle->GetURL()), |
| 342 did_commit_(false), | 342 did_commit_(false), |
| 343 page_end_reason_(END_NONE), | 343 page_end_reason_(END_NONE), |
| 344 page_end_user_initiated_info_(UserInitiatedInfo::NotUserInitiated()), | 344 page_end_user_initiated_info_(UserInitiatedInfo::NotUserInitiated()), |
| 345 started_in_foreground_(in_foreground), | 345 started_in_foreground_(in_foreground), |
| 346 timing_(CreatePageLoadTiming()), |
| 346 page_transition_(navigation_handle->GetPageTransition()), | 347 page_transition_(navigation_handle->GetPageTransition()), |
| 347 user_initiated_info_(user_initiated_info), | 348 user_initiated_info_(user_initiated_info), |
| 348 aborted_chain_size_(aborted_chain_size), | 349 aborted_chain_size_(aborted_chain_size), |
| 349 aborted_chain_size_same_url_(aborted_chain_size_same_url), | 350 aborted_chain_size_same_url_(aborted_chain_size_same_url), |
| 350 embedder_interface_(embedder_interface) { | 351 embedder_interface_(embedder_interface) { |
| 351 DCHECK(!navigation_handle->HasCommitted()); | 352 DCHECK(!navigation_handle->HasCommitted()); |
| 352 embedder_interface_->RegisterObservers(this); | 353 embedder_interface_->RegisterObservers(this); |
| 353 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnStart, navigation_handle, | 354 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnStart, navigation_handle, |
| 354 currently_committed_url, started_in_foreground_); | 355 currently_committed_url, started_in_foreground_); |
| 355 | 356 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 383 if (!failed_provisional_load_info_) | 384 if (!failed_provisional_load_info_) |
| 384 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); | 385 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); |
| 385 | 386 |
| 386 // Don't include any aborts that resulted in a new navigation, as the chain | 387 // Don't include any aborts that resulted in a new navigation, as the chain |
| 387 // length will be included in the aborter PageLoadTracker. | 388 // length will be included in the aborter PageLoadTracker. |
| 388 if (page_end_reason_ != END_RELOAD && | 389 if (page_end_reason_ != END_RELOAD && |
| 389 page_end_reason_ != END_FORWARD_BACK && | 390 page_end_reason_ != END_FORWARD_BACK && |
| 390 page_end_reason_ != END_NEW_NAVIGATION) { | 391 page_end_reason_ != END_NEW_NAVIGATION) { |
| 391 LogAbortChainHistograms(nullptr); | 392 LogAbortChainHistograms(nullptr); |
| 392 } | 393 } |
| 393 } else if (timing_.IsEmpty()) { | 394 } else if (page_load_metrics::IsEmpty(*timing_)) { |
| 394 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 395 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
| 395 } | 396 } |
| 396 | 397 |
| 397 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 398 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 398 for (const auto& observer : observers_) { | 399 for (const auto& observer : observers_) { |
| 399 if (failed_provisional_load_info_) { | 400 if (failed_provisional_load_info_) { |
| 400 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); | 401 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); |
| 401 } else if (did_commit_) { | 402 } else if (did_commit_) { |
| 402 observer->OnComplete(timing_, info); | 403 observer->OnComplete(*timing_, info); |
| 403 } | 404 } |
| 404 } | 405 } |
| 405 } | 406 } |
| 406 | 407 |
| 407 void PageLoadTracker::LogAbortChainHistograms( | 408 void PageLoadTracker::LogAbortChainHistograms( |
| 408 content::NavigationHandle* final_navigation) { | 409 content::NavigationHandle* final_navigation) { |
| 409 if (aborted_chain_size_ == 0) | 410 if (aborted_chain_size_ == 0) |
| 410 return; | 411 return; |
| 411 // Note that this could be broken out by this navigation's abort type, if more | 412 // Note that this could be broken out by this navigation's abort type, if more |
| 412 // granularity is needed. Add one to the chain size to count the current | 413 // 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... |
| 459 // Only log the first time we background in a given page load. | 460 // Only log the first time we background in a given page load. |
| 460 if (background_time_.is_null()) { | 461 if (background_time_.is_null()) { |
| 461 // Make sure we either started in the foreground and haven't been | 462 // Make sure we either started in the foreground and haven't been |
| 462 // foregrounded yet, or started in the background and have already been | 463 // foregrounded yet, or started in the background and have already been |
| 463 // foregrounded. | 464 // foregrounded. |
| 464 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); | 465 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); |
| 465 background_time_ = base::TimeTicks::Now(); | 466 background_time_ = base::TimeTicks::Now(); |
| 466 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); | 467 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); |
| 467 } | 468 } |
| 468 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 469 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 469 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, timing_, info); | 470 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, *timing_, info); |
| 470 } | 471 } |
| 471 | 472 |
| 472 void PageLoadTracker::WebContentsShown() { | 473 void PageLoadTracker::WebContentsShown() { |
| 473 // Only log the first time we foreground in a given page load. | 474 // Only log the first time we foreground in a given page load. |
| 474 if (foreground_time_.is_null()) { | 475 if (foreground_time_.is_null()) { |
| 475 // Make sure we either started in the background and haven't been | 476 // Make sure we either started in the background and haven't been |
| 476 // backgrounded yet, or started in the foreground and have already been | 477 // backgrounded yet, or started in the foreground and have already been |
| 477 // backgrounded. | 478 // backgrounded. |
| 478 DCHECK_NE(started_in_foreground_, background_time_.is_null()); | 479 DCHECK_NE(started_in_foreground_, background_time_.is_null()); |
| 479 foreground_time_ = base::TimeTicks::Now(); | 480 foreground_time_ = base::TimeTicks::Now(); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 } | 543 } |
| 543 | 544 |
| 544 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { | 545 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { |
| 545 if (!app_entered_background_) { | 546 if (!app_entered_background_) { |
| 546 RecordAppBackgroundPageLoadCompleted(false); | 547 RecordAppBackgroundPageLoadCompleted(false); |
| 547 app_entered_background_ = true; | 548 app_entered_background_ = true; |
| 548 } | 549 } |
| 549 | 550 |
| 550 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 551 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 551 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground, | 552 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground, |
| 552 timing_, info); | 553 *timing_, info); |
| 553 } | 554 } |
| 554 | 555 |
| 555 void PageLoadTracker::NotifyClientRedirectTo( | 556 void PageLoadTracker::NotifyClientRedirectTo( |
| 556 const PageLoadTracker& destination) { | 557 const PageLoadTracker& destination) { |
| 557 if (timing_.paint_timing.first_paint) { | 558 if (timing_->paint_timing->first_paint) { |
| 558 base::TimeTicks first_paint_time = | 559 base::TimeTicks first_paint_time = |
| 559 navigation_start() + timing_.paint_timing.first_paint.value(); | 560 navigation_start() + timing_->paint_timing->first_paint.value(); |
| 560 base::TimeDelta first_paint_to_navigation; | 561 base::TimeDelta first_paint_to_navigation; |
| 561 if (destination.navigation_start() > first_paint_time) | 562 if (destination.navigation_start() > first_paint_time) |
| 562 first_paint_to_navigation = | 563 first_paint_to_navigation = |
| 563 destination.navigation_start() - first_paint_time; | 564 destination.navigation_start() - first_paint_time; |
| 564 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation, | 565 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation, |
| 565 first_paint_to_navigation); | 566 first_paint_to_navigation); |
| 566 } else { | 567 } else { |
| 567 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true); | 568 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true); |
| 568 } | 569 } |
| 569 } | 570 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 584 } | 585 } |
| 585 } | 586 } |
| 586 | 587 |
| 587 void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, | 588 void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, |
| 588 const PageLoadMetadata& new_metadata) { | 589 const PageLoadMetadata& new_metadata) { |
| 589 // Throw away IPCs that are not relevant to the current navigation. | 590 // Throw away IPCs that are not relevant to the current navigation. |
| 590 // Two timing structures cannot refer to the same navigation if they indicate | 591 // Two timing structures cannot refer to the same navigation if they indicate |
| 591 // that a navigation started at different times, so a new timing struct with a | 592 // that a navigation started at different times, so a new timing struct with a |
| 592 // different start time from an earlier struct is considered invalid. | 593 // different start time from an earlier struct is considered invalid. |
| 593 const bool valid_timing_descendent = | 594 const bool valid_timing_descendent = |
| 594 timing_.navigation_start.is_null() || | 595 timing_->navigation_start.is_null() || |
| 595 timing_.navigation_start == new_timing.navigation_start; | 596 timing_->navigation_start == new_timing.navigation_start; |
| 596 if (!valid_timing_descendent) { | 597 if (!valid_timing_descendent) { |
| 597 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT); | 598 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT); |
| 598 return; | 599 return; |
| 599 } | 600 } |
| 600 | 601 |
| 601 // Ensure flags sent previously are still present in the new metadata fields. | 602 // Ensure flags sent previously are still present in the new metadata fields. |
| 602 const bool valid_behavior_descendent = | 603 const bool valid_behavior_descendent = |
| 603 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) == | 604 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) == |
| 604 main_frame_metadata_.behavior_flags; | 605 main_frame_metadata_.behavior_flags; |
| 605 if (!valid_behavior_descendent) { | 606 if (!valid_behavior_descendent) { |
| 606 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); | 607 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); |
| 607 return; | 608 return; |
| 608 } | 609 } |
| 609 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing); | 610 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing); |
| 610 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status, | 611 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status, |
| 611 internal::LAST_PAGE_LOAD_TIMING_STATUS); | 612 internal::LAST_PAGE_LOAD_TIMING_STATUS); |
| 612 if (status != internal::VALID) { | 613 if (status != internal::VALID) { |
| 613 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); | 614 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); |
| 614 return; | 615 return; |
| 615 } | 616 } |
| 616 | 617 |
| 617 DCHECK(did_commit_); // OnCommit() must be called first. | 618 DCHECK(did_commit_); // OnCommit() must be called first. |
| 618 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() | 619 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() |
| 619 // must be called before DispatchObserverTimingCallbacks, but its | 620 // must be called before DispatchObserverTimingCallbacks, but its |
| 620 // implementation depends on the state of main_frame_metadata_, so we need | 621 // implementation depends on the state of main_frame_metadata_, so we need |
| 621 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. | 622 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. |
| 622 // Thus, we make a copy of timing here, update timing_ and | 623 // Thus, we make a copy of timing here, update timing_ and |
| 623 // main_frame_metadata_, and then proceed to dispatch the observer timing | 624 // main_frame_metadata_, and then proceed to dispatch the observer timing |
| 624 // callbacks. | 625 // callbacks. |
| 625 const PageLoadTiming last_timing = timing_; | 626 mojo::StructPtr<PageLoadTiming> last_timing = std::move(timing_); |
| 626 timing_ = new_timing; | 627 timing_ = new_timing.Clone(); |
| 627 | 628 |
| 628 const PageLoadMetadata last_metadata = main_frame_metadata_; | 629 const PageLoadMetadata last_metadata = main_frame_metadata_; |
| 629 main_frame_metadata_ = new_metadata; | 630 main_frame_metadata_ = new_metadata; |
| 630 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 631 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 631 for (const auto& observer : observers_) { | 632 for (const auto& observer : observers_) { |
| 632 DispatchObserverTimingCallbacks(observer.get(), last_timing, new_timing, | 633 DispatchObserverTimingCallbacks(observer.get(), *last_timing, new_timing, |
| 633 last_metadata, info); | 634 last_metadata, info); |
| 634 } | 635 } |
| 635 } | 636 } |
| 636 | 637 |
| 637 void PageLoadTracker::OnStartedResource( | 638 void PageLoadTracker::OnStartedResource( |
| 638 const ExtraRequestStartInfo& extra_request_start_info) { | 639 const ExtraRequestStartInfo& extra_request_start_info) { |
| 639 for (const auto& observer : observers_) { | 640 for (const auto& observer : observers_) { |
| 640 observer->OnStartedResource(extra_request_start_info); | 641 observer->OnStartedResource(extra_request_start_info); |
| 641 } | 642 } |
| 642 } | 643 } |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 819 observer->MediaStartedPlaying(video_type, is_in_main_frame); | 820 observer->MediaStartedPlaying(video_type, is_in_main_frame); |
| 820 } | 821 } |
| 821 | 822 |
| 822 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, | 823 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, |
| 823 base::TimeDelta actual_delay) { | 824 base::TimeDelta actual_delay) { |
| 824 for (const auto& observer : observers_) | 825 for (const auto& observer : observers_) |
| 825 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); | 826 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); |
| 826 } | 827 } |
| 827 | 828 |
| 828 } // namespace page_load_metrics | 829 } // namespace page_load_metrics |
| OLD | NEW |