1 // Copyright 2014 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.
5 #import "ios/chrome/browser/net/metrics_network_client_manager.h"
7 #import "base/ios/weak_nsobject.h"
8 #import "base/location.h"
9 #include "base/mac/bind_objc_block.h"
10 #include "base/mac/scoped_nsobject.h"
11 #include "base/metrics/histogram.h"
12 #import "ios/chrome/browser/net/metrics_network_client.h"
13 #include "ios/web/public/web_thread.h"
16 @interface PageLoadTimeRecord ()
18 @property(nonatomic, readonly) GURL url;
19 @property(nonatomic, readonly) base::TimeTicks creationTime;
20 @property(nonatomic, assign) BOOL alreadyCounted;
22 - (instancetype)initWithURL:(const GURL&)url time:(base::TimeTicks)time;
26 @implementation PageLoadTimeRecord {
28 base::TimeTicks _creationTime;
33 @synthesize url = _url;
34 @synthesize creationTime = _creationTime;
35 @synthesize alreadyCounted = _alreadyCounted;
36 @synthesize dataProxyUsed = _dataProxyUsed;
38 - (instancetype)initWithURL:(const GURL&)url time:(base::TimeTicks)time {
39 if ((self = [super init])) {
48 @interface MetricsNetworkClientManager ()
50 // IO-thread-only methods.
51 - (void)handlePageLoadStarted:(const GURL&)url;
52 - (void)handlePageLoadCompleted;
56 @implementation MetricsNetworkClientManager {
57 // Set of page load time objects created. Beyond deallocation and
58 // creation, should only be accessed on the IO thread.
59 base::scoped_nsobject<NSMutableSet> _pageLoadTimes;
60 // Current URL being loaded by the tab that owns this object. Only accessible
65 - (instancetype)init {
66 if ((self = [super init])) {
67 _pageLoadTimes.reset([[NSMutableSet set] retain]);
72 - (Class)clientClass {
73 return [MetricsNetworkClient class];
76 #pragma mark CRWForwardingNetworkClientFactory methods
78 - (CRNForwardingNetworkClient*)clientHandlingRequest:
79 (const net::URLRequest&)request {
80 return [[[MetricsNetworkClient alloc] initWithManager:self] autorelease];
83 #pragma mark - public UI-thread methods
85 - (void)pageLoadStarted:(GURL)url {
86 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
87 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
88 [self handlePageLoadStarted:url];
92 - (void)pageLoadCompleted {
93 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
94 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
95 [self handlePageLoadCompleted];
99 #pragma mark - public IO-thread methods
101 - (PageLoadTimeRecord*)recordForPageLoad:(const GURL&)url
102 time:(base::TimeTicks)time {
103 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::IO);
104 base::scoped_nsobject<PageLoadTimeRecord> plt;
105 if (!_pageURL.spec().empty() && url == _pageURL) {
106 plt.reset([[PageLoadTimeRecord alloc] initWithURL:url time:time]);
107 [_pageLoadTimes addObject:plt];
112 #pragma mark - IO-thread handlers for UI thread methods.
114 - (void)handlePageLoadStarted:(const GURL&)url {
115 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::IO);
116 [_pageLoadTimes removeAllObjects];
120 - (void)handlePageLoadCompleted {
121 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::IO);
122 for (PageLoadTimeRecord* plt in _pageLoadTimes.get()) {
123 if (plt.url == _pageURL && !plt.alreadyCounted) {
124 plt.alreadyCounted = YES;
125 base::TimeDelta elapsed = base::TimeTicks::Now() - plt.creationTime;
126 if (plt.dataProxyUsed) {
127 UMA_HISTOGRAM_MEDIUM_TIMES(
128 "Tabs.iOS_PostRedirectPLT_DataReductionProxy", elapsed);
130 UMA_HISTOGRAM_MEDIUM_TIMES("Tabs.iOS_PostRedirectPLT", elapsed);