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 |