- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / metrics / perf_provider_chromeos.cc
1 // Copyright (c) 2012 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 <string>
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/metrics/histogram.h"
13 #include "base/rand_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "chrome/browser/metrics/perf_provider_chromeos.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_list.h"
20 #include "chrome/browser/ui/browser_list_observer.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "chromeos/dbus/debug_daemon_client.h"
24 #include "content/public/browser/browser_thread.h"
25
26 namespace {
27
28 // Default time in seconds between invocations of perf.
29 // This period is roughly 6.5 hours.
30 // This is chosen to be relatively prime with the number of seconds in:
31 // - one minute (60)
32 // - one hour (3600)
33 // - one day (86400)
34 const size_t kPerfCommandIntervalDefaultSeconds = 23093;
35
36 // The first collection interval is different from the interval above. This is
37 // because we want to collect the first profile quickly after Chrome is started.
38 // If this period is too long, the user will log off and Chrome will be killed
39 // before it is triggered. The following 2 variables determine the upper and
40 // lower bound on the interval.
41 // The reason we do not always want to collect the initial profile after a fixed
42 // period is to not over-represent task X in the profile where task X always
43 // runs at a fixed period after start-up. By selecting a period randomly between
44 // a lower and upper bound, we will hopefully collect a more fair profile.
45 const size_t kPerfCommandStartIntervalLowerBoundMinutes = 10;
46
47 const size_t kPerfCommandStartIntervalUpperBoundMinutes = 20;
48
49 // Default time in seconds perf is run for.
50 const size_t kPerfCommandDurationDefaultSeconds = 2;
51
52 // Enumeration representing success and various failure modes for collecting and
53 // sending perf data.
54 enum GetPerfDataOutcome {
55   SUCCESS,
56   NOT_READY_TO_UPLOAD,
57   NOT_READY_TO_COLLECT,
58   INCOGNITO_ACTIVE,
59   INCOGNITO_LAUNCHED,
60   PROTOBUF_NOT_PARSED,
61   NUM_OUTCOMES
62 };
63
64 // Name of the histogram that represents the success and various failure modes
65 // for collecting and sending perf data.
66 const char kGetPerfDataOutcomeHistogram[] = "UMA.Perf.GetData";
67
68 void AddToPerfHistogram(GetPerfDataOutcome outcome) {
69   UMA_HISTOGRAM_ENUMERATION(kGetPerfDataOutcomeHistogram,
70                             outcome,
71                             NUM_OUTCOMES);
72 }
73
74 } // namespace
75
76
77 namespace metrics {
78
79 // This class must be created and used on the UI thread. It watches for any
80 // incognito window being opened from the time it is instantiated to the time it
81 // is destroyed.
82 class WindowedIncognitoObserver : public chrome::BrowserListObserver {
83  public:
84   WindowedIncognitoObserver() : incognito_launched_(false) {
85     BrowserList::AddObserver(this);
86   }
87
88   virtual ~WindowedIncognitoObserver() {
89     BrowserList::RemoveObserver(this);
90   }
91
92   // This method can be checked to see whether any incognito window has been
93   // opened since the time this object was created.
94   bool incognito_launched() {
95     return incognito_launched_;
96   }
97
98  private:
99   // chrome::BrowserListObserver implementation.
100   virtual void OnBrowserAdded(Browser* browser) OVERRIDE {
101     if (browser->profile()->IsOffTheRecord())
102       incognito_launched_ = true;
103   }
104
105   bool incognito_launched_;
106 };
107
108 PerfProvider::PerfProvider()
109       : state_(READY_TO_COLLECT),
110       weak_factory_(this) {
111   size_t collection_interval_minutes = base::RandInt(
112       kPerfCommandStartIntervalLowerBoundMinutes,
113       kPerfCommandStartIntervalUpperBoundMinutes);
114   ScheduleCollection(base::TimeDelta::FromMinutes(collection_interval_minutes));
115 }
116
117 PerfProvider::~PerfProvider() {}
118
119 bool PerfProvider::GetPerfData(PerfDataProto* perf_data_proto) {
120   DCHECK(CalledOnValidThread());
121   if (state_ != READY_TO_UPLOAD) {
122     AddToPerfHistogram(NOT_READY_TO_UPLOAD);
123     return false;
124   }
125
126   *perf_data_proto = perf_data_proto_;
127   state_ = READY_TO_COLLECT;
128
129   AddToPerfHistogram(SUCCESS);
130   return true;
131 }
132
133 void PerfProvider::ScheduleCollection(const base::TimeDelta& interval) {
134   DCHECK(CalledOnValidThread());
135   if (timer_.IsRunning())
136     return;
137
138   timer_.Start(FROM_HERE, interval, this,
139                &PerfProvider::CollectIfNecessaryAndReschedule);
140 }
141
142 void PerfProvider::CollectIfNecessary() {
143   DCHECK(CalledOnValidThread());
144   if (state_ != READY_TO_COLLECT) {
145     AddToPerfHistogram(NOT_READY_TO_COLLECT);
146     return;
147   }
148
149   // For privacy reasons, Chrome should only collect perf data if there is no
150   // incognito session active (or gets spawned during the collection).
151   if (BrowserList::IsOffTheRecordSessionActive()) {
152     AddToPerfHistogram(INCOGNITO_ACTIVE);
153     return;
154   }
155
156   scoped_ptr<WindowedIncognitoObserver> incognito_observer(
157       new WindowedIncognitoObserver);
158
159   chromeos::DebugDaemonClient* client =
160       chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
161
162   base::TimeDelta collection_duration = base::TimeDelta::FromSeconds(
163       kPerfCommandDurationDefaultSeconds);
164
165   client->GetPerfData(collection_duration.InSeconds(),
166                       base::Bind(&PerfProvider::ParseProtoIfValid,
167                                  weak_factory_.GetWeakPtr(),
168                                  base::Passed(&incognito_observer)));
169 }
170
171 void PerfProvider::CollectIfNecessaryAndReschedule() {
172   CollectIfNecessary();
173   ScheduleCollection(
174       base::TimeDelta::FromSeconds(kPerfCommandIntervalDefaultSeconds));
175 }
176
177 void PerfProvider::ParseProtoIfValid(
178     scoped_ptr<WindowedIncognitoObserver> incognito_observer,
179     const std::vector<uint8>& data) {
180   DCHECK(CalledOnValidThread());
181
182   if (incognito_observer->incognito_launched()) {
183     AddToPerfHistogram(INCOGNITO_LAUNCHED);
184     return;
185   }
186
187   if (!perf_data_proto_.ParseFromArray(data.data(), data.size())) {
188     AddToPerfHistogram(PROTOBUF_NOT_PARSED);
189     perf_data_proto_.Clear();
190     return;
191   }
192
193   state_ = READY_TO_UPLOAD;
194 }
195 } // namespace metrics