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

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: Changed top-level UMA name to PageLoad 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.
nasko 2015/09/14 23:32:24 Maybe DCHECK these conditions if they should never
Charlie Harrison 2015/09/16 22:37:38 Sure. I'm keeping the outer ifs for clarity though
33 if (timing.navigation_start.is_null())
34 return false;
35
36 // If we have a dom content loaded event, we should have a response start.
nasko 2015/09/14 23:32:24 nit: DOM
37 if (!timing.dom_content_loaded_event_start.is_zero()) {
38 if (timing.response_start.is_zero() ||
39 timing.dom_content_loaded_event_start < timing.response_start) {
40 return false;
41 }
42 }
43
44 // If we have a load event, we should have both a response start and a DCL.
45 if (!timing.load_event_start.is_zero()) {
46 if (timing.response_start.is_zero() ||
47 timing.dom_content_loaded_event_start.is_zero() ||
48 timing.load_event_start < timing.dom_content_loaded_event_start ||
49 timing.load_event_start < timing.response_start) {
50 return false;
51 }
52 }
53
54 return true;
55 }
56
57 } // namespace
58
59 MetricsWebContentsObserver::MetricsWebContentsObserver(
60 content::WebContents* web_contents)
61 : content::WebContentsObserver(web_contents), current_host_(nullptr) {}
62
63 // As a tab helper, this object is tied to a single WebContent
nasko 2015/09/14 23:32:24 How is this a tab helper? Isn't it WebContentsObse
Charlie Harrison 2015/09/16 22:37:38 A tab helper is a WebContentsObserver. See https:/
nasko 2015/09/17 20:58:43 Yes, tab helper is WebContentsObserver. WebContent
Charlie Harrison 2015/09/17 21:57:27 Maybe my understanding of tab helper is wrong, but
nasko 2015/09/17 23:23:29 I think this is my bad. I missed the part where th
64 // for its entire lifetime.
65 MetricsWebContentsObserver::~MetricsWebContentsObserver() {
66 RecordTimingHistograms();
67 }
68
69 void MetricsWebContentsObserver::FrameDeleted(
70 content::RenderFrameHost* render_frame_host) {
71 if (render_frame_host == current_host_)
72 current_host_ = nullptr;
73 }
74
75 bool MetricsWebContentsObserver::OnMessageReceived(
76 const IPC::Message& message,
77 content::RenderFrameHost* render_frame_host) {
78 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
79 bool handled = true;
80 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message,
81 render_frame_host)
82 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated)
83 IPC_MESSAGE_UNHANDLED(handled = false)
84 IPC_END_MESSAGE_MAP()
85 return handled;
86 }
87
88 void MetricsWebContentsObserver::DidCommitNavigation(
89 content::NavigationHandle* navigation_handle) {
90 if (navigation_handle->IsInMainFrame() && !navigation_handle->IsSamePage())
91 RecordTimingHistograms();
92 if (IsRelevantNavigation(navigation_handle)) {
nasko 2015/09/14 23:32:24 nit: No need for {} for single line if statements.
93 current_timing_.reset(new PageLoadTiming());
94 }
95 }
96
97 // This will occur when the process for the main RenderFrameHost exits.
98 // This will happen with a normal exit or a crash.
99 void MetricsWebContentsObserver::RenderProcessGone(
100 base::TerminationStatus status) {
101 RecordTimingHistograms();
102 }
103
104 #define PAGE_LOAD_HISTOGRAM(name, sample) \
105 UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \
106 base::TimeDelta::FromMilliseconds(10), \
107 base::TimeDelta::FromMinutes(10), 100);
108
109 void MetricsWebContentsObserver::OnTimingUpdated(
110 content::RenderFrameHost* render_frame_host,
111 const PageLoadTiming& timing) {
112 if (!current_timing_)
113 return;
114
115 // We may receive notifications from frames that have been navigated away
116 // from. We simply ignore them.
117 if (render_frame_host != web_contents()->GetMainFrame())
118 return;
119
120 // See comment in IsRelevantNavigation about
121 // browser/renderer url disagreement (newtab).
nasko 2015/09/14 23:32:24 This comment doesn't seem related to the following
Charlie Harrison 2015/09/16 22:37:38 It's related, I updated it for clarity.
122 if (!web_contents()->GetLastCommittedURL().SchemeIsHTTPOrHTTPS())
123 return;
124
125 // Throw away IPCs that are not relevant to the current navigation.
126 if (!current_timing_->navigation_start.is_null() &&
127 timing.navigation_start != current_timing_->navigation_start) {
128 // TODO(csharrison) uma log a counter here
129 return;
130 }
131
132 if (current_timing_->IsEmpty())
133 current_host_ = render_frame_host;
nasko 2015/09/14 23:32:24 Please avoid storing this value. I don't see what
Charlie Harrison 2015/09/16 22:37:38 Fair enough. It was just to sanity check that a si
134 else
135 DCHECK_EQ(render_frame_host, current_host_);
136 *current_timing_ = timing;
137 }
138
139 void MetricsWebContentsObserver::RecordTimingHistograms() {
140 if (!current_timing_ || !IsValidPageLoadTiming(*current_timing_))
141 return;
142
143 if (!current_timing_->dom_content_loaded_event_start.is_zero()) {
144 PAGE_LOAD_HISTOGRAM(
145 "PageLoad.Timing.Navigation.To.DOMContentLoadedEventFired",
146 current_timing_->dom_content_loaded_event_start);
147 }
148
149 if (!current_timing_->load_event_start.is_zero()) {
150 PAGE_LOAD_HISTOGRAM("PageLoad.Timing.Navigation.To.LoadEventFired",
151 current_timing_->load_event_start);
152 }
153
154 if (!current_timing_->first_layout.is_zero()) {
155 PAGE_LOAD_HISTOGRAM("PageLoad.Timing.Navigation.To.FirstLayout",
156 current_timing_->first_layout);
157 }
158 current_timing_.reset();
159 }
160
161 bool MetricsWebContentsObserver::IsRelevantNavigation(
162 content::NavigationHandle* navigation_handle) {
163 // The url we see from the renderer side is not always the same as what
164 // we see from the browser side (e.g. chrome://newtab). We want to be
165 // sure here that we aren't logging UMA for internal pages.
166 const GURL& browser_url = web_contents()->GetLastCommittedURL();
167 return navigation_handle->IsInMainFrame() &&
168 !navigation_handle->IsSamePage() &&
169 navigation_handle->HasCommittedDocument() &&
170 navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() &&
171 browser_url.SchemeIsHTTPOrHTTPS();
nasko 2015/09/14 23:32:24 Why do you need to check both the browser url and
Charlie Harrison 2015/09/16 22:37:38 Yes except for special cases like https://www.goog
172 }
173
174 } // namespace page_load_metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698