12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/rand_util.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/metrics/perf_provider_chromeos.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_list_observer.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/dbus/debug_daemon_client.h"
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/browser/notification_service.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Partition time since login into successive intervals of this size. In each
3046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// interval, pick a random time to collect a profile.
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst size_t kPerfProfilingIntervalMs = 3 * 60 * 60 * 1000;
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Default time in seconds perf is run for.
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const size_t kPerfCommandDurationDefaultSeconds = 2;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Limit the total size of protobufs that can be cached, so they don't take up
37c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// too much memory. If the size of cached protobufs exceeds this value, stop
38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// collecting further perf data. The current value is 4 MB.
39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024;
40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// There may be too many suspends to collect a profile each time there is a
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// resume. To limit the number of profiles, collect one for 1 in 10 resumes.
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Adjust this number as needed.
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const int kResumeSamplingFactor = 10;
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// There may be too many session restores to collect a profile each time. Limit
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// the collection rate by collecting one per 10 restores. Adjust this number as
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// needed.
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kRestoreSessionSamplingFactor = 10;
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// This is used to space out session restore collections in the face of several
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// notifications in a short period of time. There should be no less than this
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// much time between collections. The current value is 30 seconds.
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kMinIntervalBetweenSessionRestoreCollectionsMs = 30 * 1000;
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// If collecting after a resume, add a random delay before collecting. The delay
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// should be randomly selected between 0 and this value. Currently the value is
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// equal to 5 seconds.
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kMaxResumeCollectionDelayMs = 5 * 1000;
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// If collecting after a session restore, add a random delay before collecting.
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// The delay should be randomly selected between 0 and this value. Currently the
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// value is equal to 10 seconds.
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst int kMaxRestoreSessionCollectionDelayMs = 10 * 1000;
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
66a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Enumeration representing success and various failure modes for collecting and
67a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// sending perf data.
68a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)enum GetPerfDataOutcome {
69a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  SUCCESS,
70a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  NOT_READY_TO_UPLOAD,
71a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  NOT_READY_TO_COLLECT,
72a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  INCOGNITO_ACTIVE,
73a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  INCOGNITO_LAUNCHED,
74a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  PROTOBUF_NOT_PARSED,
75a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  NUM_OUTCOMES
76a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)};
77a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
78a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Name of the histogram that represents the success and various failure modes
79a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// for collecting and sending perf data.
80a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)const char kGetPerfDataOutcomeHistogram[] = "UMA.Perf.GetData";
81a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
82a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void AddToPerfHistogram(GetPerfDataOutcome outcome) {
83a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION(kGetPerfDataOutcomeHistogram,
84a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                            outcome,
85a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                            NUM_OUTCOMES);
86a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
87a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Returns true if a normal user is logged in. Returns false otherwise (e.g. if
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// logged in as a guest or as a kiosk app).
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool IsNormalUserLoggedIn() {
916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return chromeos::LoginState::Get()->IsUserAuthenticated();
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace metrics {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This class must be created and used on the UI thread. It watches for any
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// incognito window being opened from the time it is instantiated to the time it
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is destroyed.
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class WindowedIncognitoObserver : public chrome::BrowserListObserver {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WindowedIncognitoObserver() : incognito_launched_(false) {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserList::AddObserver(this);
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~WindowedIncognitoObserver() {
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserList::RemoveObserver(this);
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This method can be checked to see whether any incognito window has been
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // opened since the time this object was created.
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool incognito_launched() {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return incognito_launched_;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // chrome::BrowserListObserver implementation.
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnBrowserAdded(Browser* browser) OVERRIDE {
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (browser->profile()->IsOffTheRecord())
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      incognito_launched_ = true;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool incognito_launched_;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PerfProvider::PerfProvider()
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      : login_observer_(this),
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        next_profiling_interval_start_(base::TimeTicks::Now()),
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        weak_factory_(this) {
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Register the login observer with LoginState.
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  chromeos::LoginState::Get()->AddObserver(&login_observer_);
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Register as an observer of power manager events.
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      AddObserver(this);
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Register as an observer of session restore.
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // TODO(sque): clean this up to use something other than notifications.
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  session_restore_registrar_.Add(
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this,
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chrome::NOTIFICATION_SESSION_RESTORE_DONE,
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      content::NotificationService::AllBrowserContextsAndSources());
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Check the login state. At the time of writing, this class is instantiated
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // before login. A subsequent login would activate the profiling. However,
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // that behavior may change in the future so that the user is already logged
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // when this class is instantiated. By calling LoggedInStateChanged() here,
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // PerfProvider will recognize that the system is already logged in.
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  login_observer_.LoggedInStateChanged();
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PerfProvider::~PerfProvider() {
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  chromeos::LoginState::Get()->RemoveObserver(&login_observer_);
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool PerfProvider::GetSampledProfiles(
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    std::vector<SampledProfile>* sampled_profiles) {
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
161c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (cached_perf_data_.empty()) {
162a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    AddToPerfHistogram(NOT_READY_TO_UPLOAD);
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
164a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  sampled_profiles->swap(cached_perf_data_);
167c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  cached_perf_data_.clear();
168a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
169a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  AddToPerfHistogram(SUCCESS);
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PerfProvider::LoginObserver::LoginObserver(PerfProvider* perf_provider)
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : perf_provider_(perf_provider) {}
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PerfProvider::LoginObserver::LoggedInStateChanged() {
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (IsNormalUserLoggedIn())
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    perf_provider_->OnUserLoggedIn();
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    perf_provider_->Deactivate();
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PerfProvider::SuspendDone(const base::TimeDelta& sleep_duration) {
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // A zero value for the suspend duration indicates that the suspend was
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // canceled. Do not collect anything if that's the case.
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (sleep_duration == base::TimeDelta())
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Do not collect a profile unless logged in. The system behavior when closing
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // the lid or idling when not logged in is currently to shut down instead of
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // suspending. But it's good to enforce the rule here in case that changes.
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!IsNormalUserLoggedIn())
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Collect a profile only 1/|kResumeSamplingFactor| of the time, to avoid
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // collecting too much data.
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (base::RandGenerator(kResumeSamplingFactor) != 0)
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Override any existing profiling.
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (timer_.IsRunning())
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    timer_.Stop();
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Randomly pick a delay before doing the collection.
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TimeDelta collection_delay =
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::TimeDelta::FromMilliseconds(
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          base::RandGenerator(kMaxResumeCollectionDelayMs));
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  timer_.Start(FROM_HERE,
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch               collection_delay,
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch               base::Bind(&PerfProvider::CollectPerfDataAfterResume,
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          weak_factory_.GetWeakPtr(),
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          sleep_duration,
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          collection_delay));
214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PerfProvider::Observe(int type,
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           const content::NotificationSource& source,
218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           const content::NotificationDetails& details) {
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Only handle session restore notifications.
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(type, chrome::NOTIFICATION_SESSION_RESTORE_DONE);
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Do not collect a profile unless logged in as a normal user.
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!IsNormalUserLoggedIn())
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Collect a profile only 1/|kRestoreSessionSamplingFactor| of the time, to
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // avoid collecting too much data and potentially causing UI latency.
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (base::RandGenerator(kRestoreSessionSamplingFactor) != 0)
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const base::TimeDelta min_interval =
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::TimeDelta::FromMilliseconds(
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          kMinIntervalBetweenSessionRestoreCollectionsMs);
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const base::TimeDelta time_since_last_collection =
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      (base::TimeTicks::Now() - last_session_restore_collection_time_);
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Do not collect if there hasn't been enough elapsed time since the last
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // collection.
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!last_session_restore_collection_time_.is_null() &&
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      time_since_last_collection < min_interval) {
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Stop any existing scheduled collection.
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (timer_.IsRunning())
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    timer_.Stop();
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Randomly pick a delay before doing the collection.
248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TimeDelta collection_delay =
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::TimeDelta::FromMilliseconds(
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          base::RandGenerator(kMaxRestoreSessionCollectionDelayMs));
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  timer_.Start(
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      collection_delay,
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&PerfProvider::CollectPerfDataAfterSessionRestore,
255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 weak_factory_.GetWeakPtr(),
256116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 collection_delay));
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
25946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void PerfProvider::OnUserLoggedIn() {
26046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  login_time_ = base::TimeTicks::Now();
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ScheduleIntervalCollection();
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PerfProvider::Deactivate() {
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Stop the timer, but leave |cached_perf_data_| intact.
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  timer_.Stop();
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PerfProvider::ScheduleIntervalCollection() {
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (timer_.IsRunning())
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Pick a random time in the current interval.
27546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::TimeTicks scheduled_time =
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      next_profiling_interval_start_ +
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::TimeDelta::FromMilliseconds(
27846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          base::RandGenerator(kPerfProfilingIntervalMs));
27946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // If the scheduled time has already passed in the time it took to make the
28146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // above calculations, trigger the collection event immediately.
28246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::TimeTicks now = base::TimeTicks::Now();
28346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (scheduled_time < now)
28446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scheduled_time = now;
28546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  timer_.Start(FROM_HERE, scheduled_time - now, this,
28746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)               &PerfProvider::DoPeriodicCollection);
28846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Update the profiling interval tracker to the start of the next interval.
29046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  next_profiling_interval_start_ +=
29146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::TimeDelta::FromMilliseconds(kPerfProfilingIntervalMs);
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void PerfProvider::CollectIfNecessary(
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<SampledProfile> sampled_profile) {
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
297c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Schedule another interval collection. This call makes sense regardless of
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // whether or not the current collection was interval-triggered. If it had
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // been another type of trigger event, the interval timer would have been
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // halted, so it makes sense to reschedule a new interval collection.
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ScheduleIntervalCollection();
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
304c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Do not collect further data if we've already collected a substantial amount
305c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // of data, as indicated by |kCachedPerfDataProtobufSizeThreshold|.
306c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  size_t cached_perf_data_size = 0;
307c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (size_t i = 0; i < cached_perf_data_.size(); ++i) {
308c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    cached_perf_data_size += cached_perf_data_[i].ByteSize();
309c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
310c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (cached_perf_data_size >= kCachedPerfDataProtobufSizeThreshold) {
311a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    AddToPerfHistogram(NOT_READY_TO_COLLECT);
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
313a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // For privacy reasons, Chrome should only collect perf data if there is no
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // incognito session active (or gets spawned during the collection).
317a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (BrowserList::IsOffTheRecordSessionActive()) {
318a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    AddToPerfHistogram(INCOGNITO_ACTIVE);
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
320a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<WindowedIncognitoObserver> incognito_observer(
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new WindowedIncognitoObserver);
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::DebugDaemonClient* client =
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta collection_duration = base::TimeDelta::FromSeconds(
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kPerfCommandDurationDefaultSeconds);
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client->GetPerfData(collection_duration.InSeconds(),
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      base::Bind(&PerfProvider::ParseProtoIfValid,
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 weak_factory_.GetWeakPtr(),
33446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Passed(&incognito_observer),
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 base::Passed(&sampled_profile)));
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
33846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void PerfProvider::DoPeriodicCollection() {
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<SampledProfile> sampled_profile(new SampledProfile);
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  CollectIfNecessary(sampled_profile.Pass());
343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PerfProvider::CollectPerfDataAfterResume(
346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::TimeDelta& sleep_duration,
347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::TimeDelta& time_after_resume) {
348116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Fill out a SampledProfile protobuf that will contain the collected data.
349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<SampledProfile> sampled_profile(new SampledProfile);
350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  sampled_profile->set_trigger_event(SampledProfile::RESUME_FROM_SUSPEND);
351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  sampled_profile->set_suspend_duration_ms(sleep_duration.InMilliseconds());
352116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  sampled_profile->set_ms_after_resume(time_after_resume.InMilliseconds());
353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CollectIfNecessary(sampled_profile.Pass());
355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
357116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PerfProvider::CollectPerfDataAfterSessionRestore(
358116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::TimeDelta& time_after_restore) {
359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Fill out a SampledProfile protobuf that will contain the collected data.
360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<SampledProfile> sampled_profile(new SampledProfile);
361116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION);
362116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds());
363116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
364116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CollectIfNecessary(sampled_profile.Pass());
365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  last_session_restore_collection_time_ = base::TimeTicks::Now();
366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PerfProvider::ParseProtoIfValid(
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<WindowedIncognitoObserver> incognito_observer,
370f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<SampledProfile> sampled_profile,
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<uint8>& data) {
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
374a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (incognito_observer->incognito_launched()) {
375a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    AddToPerfHistogram(INCOGNITO_LAUNCHED);
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
377a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
379c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  PerfDataProto perf_data_proto;
380c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!perf_data_proto.ParseFromArray(data.data(), data.size())) {
381a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    AddToPerfHistogram(PROTOBUF_NOT_PARSED);
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
38546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Populate a profile collection protobuf with the collected perf data and
38646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // extra metadata.
387c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  cached_perf_data_.resize(cached_perf_data_.size() + 1);
38846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  SampledProfile& collection_data = cached_perf_data_.back();
389f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  collection_data.Swap(sampled_profile.get());
390f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Fill out remaining fields of the SampledProfile protobuf.
39246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  collection_data.set_ms_after_boot(
39346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      perf_data_proto.timestamp_sec() * base::Time::kMillisecondsPerSecond);
39446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
39546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(!login_time_.is_null());
39646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  collection_data.
39746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      set_ms_after_login((base::TimeTicks::Now() - login_time_)
39846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          .InMilliseconds());
399f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
400f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Finally, store the perf data itself.
401f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  collection_data.mutable_perf_data()->Swap(&perf_data_proto);
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace metrics
405