perf_provider_chromeos.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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/process_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
26namespace {
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)
34const unsigned kPerfCommandIntervalDefaultSeconds = 23093;
35
36// Default time in seconds perf is run for.
37const unsigned kPerfCommandDurationDefaultSeconds = 2;
38
39// Enumeration representing success and various failure modes for collecting and
40// sending perf data.
41enum GetPerfDataOutcome {
42  SUCCESS,
43  NOT_READY_TO_UPLOAD,
44  NOT_READY_TO_COLLECT,
45  INCOGNITO_ACTIVE,
46  INCOGNITO_LAUNCHED,
47  PROTOBUF_NOT_PARSED,
48  NUM_OUTCOMES
49};
50
51// Name of the histogram that represents the success and various failure modes
52// for collecting and sending perf data.
53const char kGetPerfDataOutcomeHistogram[] = "UMA.Perf.GetData";
54
55void AddToPerfHistogram(GetPerfDataOutcome outcome) {
56  UMA_HISTOGRAM_ENUMERATION(kGetPerfDataOutcomeHistogram,
57                            outcome,
58                            NUM_OUTCOMES);
59}
60
61} // namespace
62
63
64namespace metrics {
65
66// This class must be created and used on the UI thread. It watches for any
67// incognito window being opened from the time it is instantiated to the time it
68// is destroyed.
69class WindowedIncognitoObserver : public chrome::BrowserListObserver {
70 public:
71  WindowedIncognitoObserver() : incognito_launched_(false) {
72    BrowserList::AddObserver(this);
73  }
74
75  virtual ~WindowedIncognitoObserver() {
76    BrowserList::RemoveObserver(this);
77  }
78
79  // This method can be checked to see whether any incognito window has been
80  // opened since the time this object was created.
81  bool incognito_launched() {
82    return incognito_launched_;
83  }
84
85 private:
86  // chrome::BrowserListObserver implementation.
87  virtual void OnBrowserAdded(Browser* browser) OVERRIDE {
88    if (browser->profile()->IsOffTheRecord())
89      incognito_launched_ = true;
90  }
91
92  bool incognito_launched_;
93};
94
95PerfProvider::PerfProvider()
96      : state_(READY_TO_COLLECT),
97      weak_factory_(this) {
98  ScheduleCollection();
99}
100
101PerfProvider::~PerfProvider() {}
102
103bool PerfProvider::GetPerfData(PerfDataProto* perf_data_proto) {
104  DCHECK(CalledOnValidThread());
105  if (state_ != READY_TO_UPLOAD) {
106    AddToPerfHistogram(NOT_READY_TO_UPLOAD);
107    return false;
108  }
109
110  *perf_data_proto = perf_data_proto_;
111  state_ = READY_TO_COLLECT;
112
113  AddToPerfHistogram(SUCCESS);
114  return true;
115}
116
117void PerfProvider::ScheduleCollection() {
118  DCHECK(CalledOnValidThread());
119  if (timer_.IsRunning())
120    return;
121
122  base::TimeDelta collection_interval = base::TimeDelta::FromSeconds(
123      kPerfCommandIntervalDefaultSeconds);
124
125  timer_.Start(FROM_HERE, collection_interval, this,
126               &PerfProvider::CollectIfNecessary);
127}
128
129void PerfProvider::CollectIfNecessary() {
130  DCHECK(CalledOnValidThread());
131  if (state_ != READY_TO_COLLECT) {
132    AddToPerfHistogram(NOT_READY_TO_COLLECT);
133    return;
134  }
135
136  // For privacy reasons, Chrome should only collect perf data if there is no
137  // incognito session active (or gets spawned during the collection).
138  if (BrowserList::IsOffTheRecordSessionActive()) {
139    AddToPerfHistogram(INCOGNITO_ACTIVE);
140    return;
141  }
142
143  scoped_ptr<WindowedIncognitoObserver> incognito_observer(
144      new WindowedIncognitoObserver);
145
146  chromeos::DebugDaemonClient* client =
147      chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
148
149  base::TimeDelta collection_duration = base::TimeDelta::FromSeconds(
150      kPerfCommandDurationDefaultSeconds);
151
152  client->GetPerfData(collection_duration.InSeconds(),
153                      base::Bind(&PerfProvider::ParseProtoIfValid,
154                                 weak_factory_.GetWeakPtr(),
155                                 base::Passed(&incognito_observer)));
156}
157
158
159void PerfProvider::ParseProtoIfValid(
160    scoped_ptr<WindowedIncognitoObserver> incognito_observer,
161    const std::vector<uint8>& data) {
162  DCHECK(CalledOnValidThread());
163
164  if (incognito_observer->incognito_launched()) {
165    AddToPerfHistogram(INCOGNITO_LAUNCHED);
166    return;
167  }
168
169  if (!perf_data_proto_.ParseFromArray(data.data(), data.size())) {
170    AddToPerfHistogram(PROTOBUF_NOT_PARSED);
171    perf_data_proto_.Clear();
172    return;
173  }
174
175  state_ = READY_TO_UPLOAD;
176}
177} // namespace metrics
178