Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: components/page_load_metrics/browser/metrics_web_contents_observer.cc

Issue 1312213010: PageLoadMetrics renderer and browser implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Nasko fixes Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
6
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "components/page_load_metrics/common/page_load_metrics_messages.h"
10 #include "components/page_load_metrics/common/page_load_timing.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/navigation_details.h"
13 #include "content/public/browser/navigation_handle.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/browser/web_contents_observer.h"
17 #include "content/public/browser/web_contents_user_data.h"
18 #include "ipc/ipc_message.h"
19 #include "ipc/ipc_message_macros.h"
20
21 DEFINE_WEB_CONTENTS_USER_DATA_KEY(
22 page_load_metrics::MetricsWebContentsObserver);
23
24 namespace page_load_metrics {
25
26 namespace {
27
28 bool IsValidPageLoadTiming(const PageLoadTiming& timing) {
29 if (timing.IsEmpty())
30 return false;
31
32 // If we have a non-empty timing, it should always have a navigation start.
33 DCHECK(!timing.navigation_start.is_null());
34
35 // If we have a DOM content loaded event, we should have a response start.
36 if (!timing.dom_content_loaded_event_start.is_zero()) {
37 DCHECK(!timing.response_start.is_zero());
38 DCHECK(timing.response_start <= timing.dom_content_loaded_event_start);
39 }
40
41 // If we have a load event, we should have both a response start and a DCL.
42 if (!timing.load_event_start.is_zero()) {
43 DCHECK(!timing.response_start.is_zero() &&
44 !timing.dom_content_loaded_event_start.is_zero());
45 DCHECK(timing.response_start <= timing.load_event_start &&
46 timing.dom_content_loaded_event_start <= timing.load_event_start);
nasko 2015/09/17 20:58:43 It seems weird to have an if block with only DCHEC
Charlie Harrison 2015/09/17 21:57:27 Done.
47 }
48
49 return true;
50 }
51
52 } // namespace
53
54 MetricsWebContentsObserver::MetricsWebContentsObserver(
55 content::WebContents* web_contents)
56 : content::WebContentsObserver(web_contents) {}
57
58 // As a tab helper, this object is tied to a single WebContents
59 // for its entire lifetime.
60 MetricsWebContentsObserver::~MetricsWebContentsObserver() {
61 RecordTimingHistograms();
62 }
63
64 bool MetricsWebContentsObserver::OnMessageReceived(
65 const IPC::Message& message,
66 content::RenderFrameHost* render_frame_host) {
67 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
68 bool handled = true;
69 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message,
70 render_frame_host)
71 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated)
72 IPC_MESSAGE_UNHANDLED(handled = false)
73 IPC_END_MESSAGE_MAP()
74 return handled;
75 }
76
77 void MetricsWebContentsObserver::DidCommitNavigation(
78 content::NavigationHandle* navigation_handle) {
79 if (navigation_handle->IsInMainFrame() && !navigation_handle->IsSamePage())
80 RecordTimingHistograms();
81 if (IsRelevantNavigation(navigation_handle))
82 current_timing_.reset(new PageLoadTiming());
83 }
84
85 // This will occur when the process for the main RenderFrameHost exits.
86 // This will happen with a normal exit or a crash.
87 void MetricsWebContentsObserver::RenderProcessGone(
88 base::TerminationStatus status) {
89 RecordTimingHistograms();
90 }
91
92 #define PAGE_LOAD_HISTOGRAM(name, sample) \
93 UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \
94 base::TimeDelta::FromMilliseconds(10), \
95 base::TimeDelta::FromMinutes(10), 100);
96
97 void MetricsWebContentsObserver::OnTimingUpdated(
98 content::RenderFrameHost* render_frame_host,
99 const PageLoadTiming& timing) {
100 if (!current_timing_)
101 return;
102
103 // We may receive notifications from frames that have been navigated away
104 // from. We simply ignore them.
105 if (render_frame_host != web_contents()->GetMainFrame())
106 return;
107
108 // For urls like chrome://newtab, the renderer and browser disagree,
109 // so we have to double check that the renderer isn't sending data from a
110 // bad url like https://www.google.com/_/chrome/newtab.
nasko 2015/09/17 20:58:43 Which claims what? It doesn't seem obvious to me w
Charlie Harrison 2015/09/17 21:57:27 We don't want to track new tab page for our metric
111 if (!web_contents()->GetLastCommittedURL().SchemeIsHTTPOrHTTPS())
112 return;
113
114 // Throw away IPCs that are not relevant to the current navigation.
115 if (!current_timing_->navigation_start.is_null() &&
116 timing.navigation_start != current_timing_->navigation_start) {
117 // TODO(csharrison) uma log a counter here
118 return;
119 }
120
121 *current_timing_ = timing;
122 }
123
124 void MetricsWebContentsObserver::RecordTimingHistograms() {
125 if (!current_timing_ || !IsValidPageLoadTiming(*current_timing_))
126 return;
127
128 if (!current_timing_->dom_content_loaded_event_start.is_zero()) {
129 PAGE_LOAD_HISTOGRAM(
130 "PageLoad.Timing.Navigation.To.DOMContentLoadedEventFired",
131 current_timing_->dom_content_loaded_event_start);
132 }
133
134 if (!current_timing_->load_event_start.is_zero()) {
135 PAGE_LOAD_HISTOGRAM("PageLoad.Timing.Navigation.To.LoadEventFired",
136 current_timing_->load_event_start);
137 }
138
139 if (!current_timing_->first_layout.is_zero()) {
140 PAGE_LOAD_HISTOGRAM("PageLoad.Timing.Navigation.To.FirstLayout",
141 current_timing_->first_layout);
142 }
143 current_timing_.reset();
144 }
145
146 bool MetricsWebContentsObserver::IsRelevantNavigation(
147 content::NavigationHandle* navigation_handle) {
148 // The url we see from the renderer side is not always the same as what
149 // we see from the browser side (e.g. chrome://newtab). We want to be
150 // sure here that we aren't logging UMA for internal pages.
151 const GURL& browser_url = web_contents()->GetLastCommittedURL();
152 return navigation_handle->IsInMainFrame() &&
153 !navigation_handle->IsSamePage() &&
154 navigation_handle->HasCommittedDocument() &&
155 navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() &&
156 browser_url.SchemeIsHTTPOrHTTPS();
157 }
158
159 } // namespace page_load_metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698