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

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: arg. 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 #include "chrome/common/pref_names.h"
18 19
19 using base::Time; 20 using base::Time;
20 using base::TimeDelta; 21 using base::TimeDelta;
21 using chromeos::VersionLoader; 22 using chromeos::VersionLoader;
22 23
23 namespace em = enterprise_management; 24 namespace em = enterprise_management;
24 25
25 namespace { 26 namespace {
26 // How many seconds of inactivity triggers the idle state. 27 // How many seconds of inactivity triggers the idle state.
27 const unsigned int kIdleStateThresholdSeconds = 300; 28 const unsigned int kIdleStateThresholdSeconds = 300;
28 29
29 // The maximum number of time periods stored in the local state. 30 // How many days in the past to store active periods for.
30 const unsigned int kMaxStoredActivePeriods = 500; 31 const unsigned int kMaxStoredPastActivityDays = 30;
31 32
32 // Stores a list of timestamps representing device active periods. 33 // How many days in the future to store active periods for.
33 const char* const kPrefDeviceActivePeriods = "device_status.active_periods"; 34 const unsigned int kMaxStoredFutureActivityDays = 2;
34 35
35 bool GetTimestamp(const ListValue* list, int index, int64* out_value) { 36 const int64 kMillisecondsPerDay = Time::kMicrosecondsPerDay / 1000;
36 std::string string_value; 37
37 if (list->GetString(index, &string_value)) 38 // Record device activity for the specified day into the given dictionary.
38 return base::StringToInt64(string_value, out_value); 39 void AddDeviceActivity(DictionaryValue* activity_times,
39 return false; 40 Time day_midnight,
41 TimeDelta activity) {
42 DCHECK(activity.InMilliseconds() < kMillisecondsPerDay);
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(prefs::kDeviceActivityTimes,
104 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(prefs::kDeviceActivityTimes);
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(prefs::kDeviceActivityTimes, *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_, prefs::kDeviceActivityTimes);
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 int active_seconds = (now - last_idle_check_).InSeconds();
169 if ((now - last_idle_check_).InSeconds() >= (2 * poll_interval)) 204 if (active_seconds < 0 ||
170 AddActivePeriod(now - TimeDelta::FromSeconds(poll_interval), now); 205 active_seconds >= static_cast<int>((2 * kPollIntervalSeconds)))
206 AddActivePeriod(now - TimeDelta::FromSeconds(kPollIntervalSeconds), now);
171 else 207 else
172 AddActivePeriod(last_idle_check_, now); 208 AddActivePeriod(last_idle_check_, now);
209
210 PruneStoredActivityPeriods(now);
173 } 211 }
174 last_idle_check_ = now; 212 last_idle_check_ = now;
175 last_idle_state_ = state;
176 } 213 }
177 214
178 void DeviceStatusCollector::GetActivityTimes( 215 void DeviceStatusCollector::GetActivityTimes(
179 em::DeviceStatusReportRequest* request) { 216 em::DeviceStatusReportRequest* request) {
180 const ListValue* active_periods = 217 DictionaryPrefUpdate update(local_state_, prefs::kDeviceActivityTimes);
181 local_state_->GetList(kPrefDeviceActivePeriods); 218 DictionaryValue* activity_times = update.Get();
182 em::TimePeriod* time_period;
183 219
184 DCHECK(active_periods->GetSize() % 2 == 0); 220 for (DictionaryValue::key_iterator it = activity_times->begin_keys();
221 it != activity_times->end_keys(); ++it) {
222 int64 start_timestamp;
223 int activity_milliseconds;
224 if (base::StringToInt64(*it, &start_timestamp) &&
225 activity_times->GetInteger(*it, &activity_milliseconds)) {
226 // This is correct even when there are leap seconds, because when a leap
227 // second occurs, two consecutive seconds have the same timestamp.
228 int64 end_timestamp = start_timestamp + kMillisecondsPerDay;
185 229
186 int period_count = active_periods->GetSize() / 2; 230 em::ActiveTimePeriod* active_period = request->add_active_period();
187 for (int i = 0; i < period_count; i++) { 231 em::TimePeriod* period = active_period->mutable_time_period();
188 int64 start, end; 232 period->set_start_timestamp(start_timestamp);
189 233 period->set_end_timestamp(end_timestamp);
190 if (!GetTimestamp(active_periods, 2 * i, &start) || 234 active_period->set_active_duration(activity_milliseconds);
191 !GetTimestamp(active_periods, 2 * i + 1, &end) || 235 } else {
192 end < start) {
193 // Something is amiss -- bail out.
194 NOTREACHED(); 236 NOTREACHED();
195 break;
196 } 237 }
197 time_period = request->add_active_time();
198 time_period->set_start_timestamp(start);
199 time_period->set_end_timestamp(end);
200 } 238 }
201 ListPrefUpdate update(local_state_, kPrefDeviceActivePeriods); 239 activity_times->Clear();
202 update.Get()->Clear();
203 } 240 }
204 241
205 void DeviceStatusCollector::GetVersionInfo( 242 void DeviceStatusCollector::GetVersionInfo(
206 em::DeviceStatusReportRequest* request) { 243 em::DeviceStatusReportRequest* request) {
207 chrome::VersionInfo version_info; 244 chrome::VersionInfo version_info;
208 request->set_browser_version(version_info.Version()); 245 request->set_browser_version(version_info.Version());
209 request->set_os_version(os_version_); 246 request->set_os_version(os_version_);
210 request->set_firmware_version(firmware_version_); 247 request->set_firmware_version(firmware_version_);
211 } 248 }
212 249
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 int type, 284 int type,
248 const content::NotificationSource& source, 285 const content::NotificationSource& source,
249 const content::NotificationDetails& details) { 286 const content::NotificationDetails& details) {
250 if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED) 287 if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED)
251 UpdateReportingSettings(); 288 UpdateReportingSettings();
252 else 289 else
253 NOTREACHED(); 290 NOTREACHED();
254 } 291 }
255 292
256 } // namespace policy 293 } // 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