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.
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"
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:
34 const size_t kPerfCommandIntervalDefaultSeconds
= 23093;
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;
47 const size_t kPerfCommandStartIntervalUpperBoundMinutes
= 20;
49 // Default time in seconds perf is run for.
50 const size_t kPerfCommandDurationDefaultSeconds
= 2;
52 // Enumeration representing success and various failure modes for collecting and
54 enum GetPerfDataOutcome
{
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";
68 void AddToPerfHistogram(GetPerfDataOutcome outcome
) {
69 UMA_HISTOGRAM_ENUMERATION(kGetPerfDataOutcomeHistogram
,
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
82 class WindowedIncognitoObserver
: public chrome::BrowserListObserver
{
84 WindowedIncognitoObserver() : incognito_launched_(false) {
85 BrowserList::AddObserver(this);
88 virtual ~WindowedIncognitoObserver() {
89 BrowserList::RemoveObserver(this);
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_
;
99 // chrome::BrowserListObserver implementation.
100 virtual void OnBrowserAdded(Browser
* browser
) OVERRIDE
{
101 if (browser
->profile()->IsOffTheRecord())
102 incognito_launched_
= true;
105 bool incognito_launched_
;
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
));
117 PerfProvider::~PerfProvider() {}
119 bool PerfProvider::GetPerfData(PerfDataProto
* perf_data_proto
) {
120 DCHECK(CalledOnValidThread());
121 if (state_
!= READY_TO_UPLOAD
) {
122 AddToPerfHistogram(NOT_READY_TO_UPLOAD
);
126 *perf_data_proto
= perf_data_proto_
;
127 state_
= READY_TO_COLLECT
;
129 AddToPerfHistogram(SUCCESS
);
133 void PerfProvider::ScheduleCollection(const base::TimeDelta
& interval
) {
134 DCHECK(CalledOnValidThread());
135 if (timer_
.IsRunning())
138 timer_
.Start(FROM_HERE
, interval
, this,
139 &PerfProvider::CollectIfNecessaryAndReschedule
);
142 void PerfProvider::CollectIfNecessary() {
143 DCHECK(CalledOnValidThread());
144 if (state_
!= READY_TO_COLLECT
) {
145 AddToPerfHistogram(NOT_READY_TO_COLLECT
);
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
);
156 scoped_ptr
<WindowedIncognitoObserver
> incognito_observer(
157 new WindowedIncognitoObserver
);
159 chromeos::DebugDaemonClient
* client
=
160 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
162 base::TimeDelta collection_duration
= base::TimeDelta::FromSeconds(
163 kPerfCommandDurationDefaultSeconds
);
165 client
->GetPerfData(collection_duration
.InSeconds(),
166 base::Bind(&PerfProvider::ParseProtoIfValid
,
167 weak_factory_
.GetWeakPtr(),
168 base::Passed(&incognito_observer
)));
171 void PerfProvider::CollectIfNecessaryAndReschedule() {
172 CollectIfNecessary();
174 base::TimeDelta::FromSeconds(kPerfCommandIntervalDefaultSeconds
));
177 void PerfProvider::ParseProtoIfValid(
178 scoped_ptr
<WindowedIncognitoObserver
> incognito_observer
,
179 const std::vector
<uint8
>& data
) {
180 DCHECK(CalledOnValidThread());
182 if (incognito_observer
->incognito_launched()) {
183 AddToPerfHistogram(INCOGNITO_LAUNCHED
);
187 if (!perf_data_proto_
.ParseFromArray(data
.data(), data
.size())) {
188 AddToPerfHistogram(PROTOBUF_NOT_PARSED
);
189 perf_data_proto_
.Clear();
193 state_
= READY_TO_UPLOAD
;
195 } // namespace metrics