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