Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: chrome/browser/policy/device_status_collector.cc

Issue 9348105: Aggregate device activity, and report per-day activity in device status reports. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase, and address Mattias' comments. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/policy/device_status_collector.h" 5 #include "chrome/browser/policy/device_status_collector.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/string_number_conversions.h" 9 #include "base/string_number_conversions.h"
10 #include "chrome/browser/chromeos/cros_settings.h" 10 #include "chrome/browser/chromeos/cros_settings.h"
11 #include "chrome/browser/chromeos/cros_settings_names.h" 11 #include "chrome/browser/chromeos/cros_settings_names.h"
12 #include "chrome/browser/chromeos/system/statistics_provider.h" 12 #include "chrome/browser/chromeos/system/statistics_provider.h"
13 #include "chrome/browser/policy/proto/device_management_backend.pb.h" 13 #include "chrome/browser/policy/proto/device_management_backend.pb.h"
14 #include "chrome/browser/prefs/pref_service.h" 14 #include "chrome/browser/prefs/pref_service.h"
15 #include "chrome/browser/prefs/scoped_user_pref_update.h" 15 #include "chrome/browser/prefs/scoped_user_pref_update.h"
16 #include "chrome/common/chrome_notification_types.h" 16 #include "chrome/common/chrome_notification_types.h"
17 #include "chrome/common/chrome_version_info.h" 17 #include "chrome/common/chrome_version_info.h"
18 18
19 using base::Time; 19 using base::Time;
20 using base::TimeDelta; 20 using base::TimeDelta;
21 using chromeos::VersionLoader; 21 using chromeos::VersionLoader;
22 22
23 namespace em = enterprise_management; 23 namespace em = enterprise_management;
24 24
25 namespace { 25 namespace {
26 // How many seconds of inactivity triggers the idle state. 26 // How many seconds of inactivity triggers the idle state.
27 const unsigned int kIdleStateThresholdSeconds = 300; 27 const unsigned int kIdleStateThresholdSeconds = 300;
28 28
29 // The maximum number of time periods stored in the local state. 29 // How many days in the past to store active periods for.
30 const unsigned int kMaxStoredActivePeriods = 500; 30 const unsigned int kMaxStoredPastActivityDays = 30;
31 31
32 // Stores a list of timestamps representing device active periods. 32 // How many days in the future to store active periods for.
33 const char* const kPrefDeviceActivePeriods = "device_status.active_periods"; 33 const unsigned int kMaxStoredFutureActivityDays = 2;
34 34
35 bool GetTimestamp(const ListValue* list, int index, int64* out_value) { 35 const char* const kPrefDeviceActivityTimes = "device_status.activity_times";
Mattias Nissler (ping if slow) 2012/02/15 16:14:47 This should go into pref_names.h/cc
Patrick Dubroy 2012/02/16 09:56:31 Done.
36 std::string string_value; 36
37 if (list->GetString(index, &string_value)) 37 // Record device activity for the specified day into the given dictionary.
38 return base::StringToInt64(string_value, out_value); 38 void AddDeviceActivity(
Mattias Nissler (ping if slow) 2012/02/15 16:14:47 nit: I think you can remove the line break after t
Patrick Dubroy 2012/02/16 09:56:31 Done.
39 return false; 39 DictionaryValue* activity_times,
40 Time day_midnight,
41 TimeDelta activity) {
42 DCHECK(activity < TimeDelta::FromDays(1));
43 int64 day_start_timestamp =
44 (day_midnight - Time::UnixEpoch()).InMilliseconds();
45 std::string day_key = base::Int64ToString(day_start_timestamp);
46 int previous_activity = 0;
47 activity_times->GetInteger(day_key, &previous_activity);
48 activity_times->SetInteger(day_key,
49 previous_activity + activity.InMilliseconds());
40 } 50 }
41 51
42 } // namespace 52 } // namespace
43 53
44 namespace policy { 54 namespace policy {
45 55
46 DeviceStatusCollector::DeviceStatusCollector( 56 DeviceStatusCollector::DeviceStatusCollector(
47 PrefService* local_state, 57 PrefService* local_state,
48 chromeos::system::StatisticsProvider* provider) 58 chromeos::system::StatisticsProvider* provider)
49 : max_stored_active_periods_(kMaxStoredActivePeriods), 59 : max_stored_past_activity_days_(kMaxStoredPastActivityDays),
60 max_stored_future_activity_days_(kMaxStoredFutureActivityDays),
50 local_state_(local_state), 61 local_state_(local_state),
51 last_idle_check_(Time()), 62 last_idle_check_(Time()),
52 last_idle_state_(IDLE_STATE_UNKNOWN),
53 statistics_provider_(provider), 63 statistics_provider_(provider),
54 report_version_info_(false), 64 report_version_info_(false),
55 report_activity_times_(false), 65 report_activity_times_(false),
56 report_boot_mode_(false) { 66 report_boot_mode_(false) {
57 timer_.Start(FROM_HERE, 67 timer_.Start(FROM_HERE,
58 TimeDelta::FromSeconds( 68 TimeDelta::FromSeconds(kPollIntervalSeconds),
59 DeviceStatusCollector::kPollIntervalSeconds),
60 this, &DeviceStatusCollector::CheckIdleState); 69 this, &DeviceStatusCollector::CheckIdleState);
61 70
62 cros_settings_ = chromeos::CrosSettings::Get(); 71 cros_settings_ = chromeos::CrosSettings::Get();
63 72
64 // Watch for changes to the individual policies that control what the status 73 // Watch for changes to the individual policies that control what the status
65 // reports contain. 74 // reports contain.
66 cros_settings_->AddSettingsObserver(chromeos::kReportDeviceVersionInfo, this); 75 cros_settings_->AddSettingsObserver(chromeos::kReportDeviceVersionInfo, this);
67 cros_settings_->AddSettingsObserver(chromeos::kReportDeviceActivityTimes, 76 cros_settings_->AddSettingsObserver(chromeos::kReportDeviceActivityTimes,
68 this); 77 this);
69 cros_settings_->AddSettingsObserver(chromeos::kReportDeviceBootMode, this); 78 cros_settings_->AddSettingsObserver(chromeos::kReportDeviceBootMode, this);
(...skipping 14 matching lines...) Expand all
84 DeviceStatusCollector::~DeviceStatusCollector() { 93 DeviceStatusCollector::~DeviceStatusCollector() {
85 cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceVersionInfo, 94 cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceVersionInfo,
86 this); 95 this);
87 cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceActivityTimes, 96 cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceActivityTimes,
88 this); 97 this);
89 cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceBootMode, this); 98 cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceBootMode, this);
90 } 99 }
91 100
92 // static 101 // static
93 void DeviceStatusCollector::RegisterPrefs(PrefService* local_state) { 102 void DeviceStatusCollector::RegisterPrefs(PrefService* local_state) {
94 local_state->RegisterListPref(kPrefDeviceActivePeriods, new ListValue); 103 local_state->RegisterDictionaryPref(
104 kPrefDeviceActivityTimes, new DictionaryValue);
95 } 105 }
96 106
97 void DeviceStatusCollector::CheckIdleState() { 107 void DeviceStatusCollector::CheckIdleState() {
98 CalculateIdleState(kIdleStateThresholdSeconds, 108 CalculateIdleState(kIdleStateThresholdSeconds,
99 base::Bind(&DeviceStatusCollector::IdleStateCallback, 109 base::Bind(&DeviceStatusCollector::IdleStateCallback,
100 base::Unretained(this))); 110 base::Unretained(this)));
101 } 111 }
102 112
103 void DeviceStatusCollector::UpdateReportingSettings() { 113 void DeviceStatusCollector::UpdateReportingSettings() {
104 // Attempt to fetch the current value of the reporting settings. 114 // Attempt to fetch the current value of the reporting settings.
(...skipping 10 matching lines...) Expand all
115 chromeos::kReportDeviceActivityTimes, &report_activity_times_); 125 chromeos::kReportDeviceActivityTimes, &report_activity_times_);
116 cros_settings_->GetBoolean( 126 cros_settings_->GetBoolean(
117 chromeos::kReportDeviceBootMode, &report_boot_mode_); 127 chromeos::kReportDeviceBootMode, &report_boot_mode_);
118 } 128 }
119 } 129 }
120 130
121 Time DeviceStatusCollector::GetCurrentTime() { 131 Time DeviceStatusCollector::GetCurrentTime() {
122 return Time::Now(); 132 return Time::Now();
123 } 133 }
124 134
125 void DeviceStatusCollector::AddActivePeriod(Time start, Time end) { 135 // Remove all out-of-range activity times from the local store.
126 // Maintain the list of active periods in a local_state pref. 136 void DeviceStatusCollector::PruneStoredActivityPeriods(Time base_time) {
127 ListPrefUpdate update(local_state_, kPrefDeviceActivePeriods); 137 const DictionaryValue* activity_times =
128 ListValue* active_periods = update.Get(); 138 local_state_->GetDictionary(kPrefDeviceActivityTimes);
129 139 if (activity_times->size() <=
130 // Cap the number of active periods that we store. 140 max_stored_past_activity_days_ + max_stored_future_activity_days_)
131 if (active_periods->GetSize() >= 2 * max_stored_active_periods_)
132 return; 141 return;
133 142
134 Time epoch = Time::UnixEpoch(); 143 Time min_time =
135 int64 start_timestamp = (start - epoch).InMilliseconds(); 144 base_time - TimeDelta::FromDays(max_stored_past_activity_days_);
136 Value* end_value = new StringValue( 145 Time max_time =
137 base::Int64ToString((end - epoch).InMilliseconds())); 146 base_time + TimeDelta::FromDays(max_stored_future_activity_days_);
147 const Time epoch = Time::UnixEpoch();
138 148
139 int list_size = active_periods->GetSize(); 149 DictionaryValue* copy = activity_times->DeepCopy();
140 DCHECK(list_size % 2 == 0); 150 for (DictionaryValue::key_iterator it = activity_times->begin_keys();
151 it != activity_times->end_keys(); ++it) {
152 int64 timestamp;
141 153
142 // Check if this period can be combined with the previous one. 154 if (base::StringToInt64(*it, &timestamp)) {
143 if (list_size > 0 && last_idle_state_ == IDLE_STATE_ACTIVE) { 155 // Remove data that is too old, or too far in the future.
144 int64 last_period_end; 156 Time day_midnight = epoch + TimeDelta::FromMilliseconds(timestamp);
145 if (GetTimestamp(active_periods, list_size - 1, &last_period_end) && 157 if (day_midnight > min_time && day_midnight < max_time)
146 last_period_end == start_timestamp) { 158 continue;
147 active_periods->Set(list_size - 1, end_value);
148 return;
149 } 159 }
160 // The entry is out of range or couldn't be parsed. Remove it.
161 copy->Remove(*it, NULL);
150 } 162 }
151 // Add a new period to the list. 163 local_state_->Set(kPrefDeviceActivityTimes, *copy);
152 active_periods->Append( 164 }
153 new StringValue(base::Int64ToString(start_timestamp))); 165
154 active_periods->Append(end_value); 166 void DeviceStatusCollector::AddActivePeriod(Time start, Time end) {
167 DCHECK(start < end);
168
169 // Maintain the list of active periods in a local_state pref.
170 DictionaryPrefUpdate update(local_state_, kPrefDeviceActivityTimes);
171 DictionaryValue* activity_times = update.Get();
172
173 Time midnight = end.LocalMidnight();
174
175 // Figure out UTC midnight on the same day as the local day.
176 Time::Exploded exploded;
177 midnight.LocalExplode(&exploded);
178 Time utc_midnight = Time::FromUTCExploded(exploded);
179
180 // Record the device activity for today.
181 TimeDelta activity_today = end - MAX(midnight, start);
182 AddDeviceActivity(activity_times, utc_midnight, activity_today);
183
184 // If this interval spans two days, record activity for yesterday too.
185 if (start < midnight) {
186 AddDeviceActivity(activity_times,
187 utc_midnight - TimeDelta::FromDays(1),
188 midnight - start);
189 }
155 } 190 }
156 191
157 void DeviceStatusCollector::IdleStateCallback(IdleState state) { 192 void DeviceStatusCollector::IdleStateCallback(IdleState state) {
158 // Do nothing if device activity reporting is disabled. 193 // Do nothing if device activity reporting is disabled.
159 if (!report_activity_times_) 194 if (!report_activity_times_)
160 return; 195 return;
161 196
162 Time now = GetCurrentTime(); 197 Time now = GetCurrentTime();
163 198
164 if (state == IDLE_STATE_ACTIVE) { 199 if (state == IDLE_STATE_ACTIVE) {
165 unsigned int poll_interval = DeviceStatusCollector::kPollIntervalSeconds; 200 // If it's been too long since the last report, or if the activity is
166 201 // negative (which can happen when the clock changes), assume a single
167 // If it's been too long since the last report, assume that the system was 202 // interval of activity.
168 // in standby, and only count a single interval of activity. 203 unsigned int active_seconds = (now - last_idle_check_).InSeconds();
169 if ((now - last_idle_check_).InSeconds() >= (2 * poll_interval)) 204 if (active_seconds < 0 || active_seconds >= (2 * kPollIntervalSeconds))
170 AddActivePeriod(now - TimeDelta::FromSeconds(poll_interval), now); 205 AddActivePeriod(now - TimeDelta::FromSeconds(kPollIntervalSeconds), now);
171 else 206 else
172 AddActivePeriod(last_idle_check_, now); 207 AddActivePeriod(last_idle_check_, now);
208
209 PruneStoredActivityPeriods(now);
173 } 210 }
174 last_idle_check_ = now; 211 last_idle_check_ = now;
175 last_idle_state_ = state;
176 } 212 }
177 213
178 void DeviceStatusCollector::GetActivityTimes( 214 void DeviceStatusCollector::GetActivityTimes(
179 em::DeviceStatusReportRequest* request) { 215 em::DeviceStatusReportRequest* request) {
180 const ListValue* active_periods = 216 DictionaryPrefUpdate update(local_state_, kPrefDeviceActivityTimes);
181 local_state_->GetList(kPrefDeviceActivePeriods); 217 DictionaryValue* activity_times = update.Get();
182 em::TimePeriod* time_period; 218 const int64 milliseconds_per_day = TimeDelta::FromDays(1).InMilliseconds();
183 219
184 DCHECK(active_periods->GetSize() % 2 == 0); 220 for (DictionaryValue::key_iterator it = activity_times->begin_keys();
185 221 it != activity_times->end_keys(); ++it) {
186 int period_count = active_periods->GetSize() / 2; 222 int64 start_timestamp;
187 for (int i = 0; i < period_count; i++) { 223 int activity_milliseconds;
188 int64 start, end; 224 if (base::StringToInt64(*it, &start_timestamp) &&
189 225 activity_times->GetInteger(*it, &activity_milliseconds)) {
190 if (!GetTimestamp(active_periods, 2 * i, &start) || 226 em::ActiveTimePeriod* active_period = request->add_active_period();
191 !GetTimestamp(active_periods, 2 * i + 1, &end) || 227 em::TimePeriod* period = active_period->mutable_time_period();
192 end < start) { 228 period->set_start_timestamp(start_timestamp);
193 // Something is amiss -- bail out. 229 period->set_end_timestamp(start_timestamp + milliseconds_per_day);
Mattias Nissler (ping if slow) 2012/02/15 16:14:47 Technically, this is incorrect for days with leap
Patrick Dubroy 2012/02/16 09:56:31 It's actually correct, because when a leap second
230 active_period->set_active_duration(activity_milliseconds);
231 } else {
194 NOTREACHED(); 232 NOTREACHED();
195 break;
196 } 233 }
197 time_period = request->add_active_time();
198 time_period->set_start_timestamp(start);
199 time_period->set_end_timestamp(end);
200 } 234 }
201 ListPrefUpdate update(local_state_, kPrefDeviceActivePeriods); 235 activity_times->Clear();
202 update.Get()->Clear();
203 } 236 }
204 237
205 void DeviceStatusCollector::GetVersionInfo( 238 void DeviceStatusCollector::GetVersionInfo(
206 em::DeviceStatusReportRequest* request) { 239 em::DeviceStatusReportRequest* request) {
207 chrome::VersionInfo version_info; 240 chrome::VersionInfo version_info;
208 request->set_browser_version(version_info.Version()); 241 request->set_browser_version(version_info.Version());
209 request->set_os_version(os_version_); 242 request->set_os_version(os_version_);
210 request->set_firmware_version(firmware_version_); 243 request->set_firmware_version(firmware_version_);
211 } 244 }
212 245
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 int type, 280 int type,
248 const content::NotificationSource& source, 281 const content::NotificationSource& source,
249 const content::NotificationDetails& details) { 282 const content::NotificationDetails& details) {
250 if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED) 283 if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED)
251 UpdateReportingSettings(); 284 UpdateReportingSettings();
252 else 285 else
253 NOTREACHED(); 286 NOTREACHED();
254 } 287 }
255 288
256 } // namespace policy 289 } // namespace policy
OLDNEW
« no previous file with comments | « chrome/browser/policy/device_status_collector.h ('k') | chrome/browser/policy/device_status_collector_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698