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