1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/policy/device_status_collector.h" 6 7 #include <limits> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/location.h" 12 #include "base/logging.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/prefs/pref_registry_simple.h" 15 #include "base/prefs/pref_service.h" 16 #include "base/prefs/scoped_user_pref_update.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/values.h" 19 #include "chrome/browser/browser_process.h" 20 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" 21 #include "chrome/browser/chromeos/settings/cros_settings.h" 22 #include "chrome/common/chrome_version_info.h" 23 #include "chrome/common/pref_names.h" 24 #include "chromeos/network/device_state.h" 25 #include "chromeos/network/network_handler.h" 26 #include "chromeos/network/network_state_handler.h" 27 #include "chromeos/settings/cros_settings_names.h" 28 #include "chromeos/system/statistics_provider.h" 29 #include "components/policy/core/common/cloud/cloud_policy_constants.h" 30 #include "components/user_manager/user_manager.h" 31 #include "components/user_manager/user_type.h" 32 #include "content/public/browser/browser_thread.h" 33 #include "policy/proto/device_management_backend.pb.h" 34 #include "third_party/cros_system_api/dbus/service_constants.h" 35 36 using base::Time; 37 using base::TimeDelta; 38 using chromeos::VersionLoader; 39 40 namespace em = enterprise_management; 41 42 namespace { 43 // How many seconds of inactivity triggers the idle state. 44 const int kIdleStateThresholdSeconds = 300; 45 46 // How many days in the past to store active periods for. 47 const unsigned int kMaxStoredPastActivityDays = 30; 48 49 // How many days in the future to store active periods for. 50 const unsigned int kMaxStoredFutureActivityDays = 2; 51 52 // How often, in seconds, to update the device location. 53 const unsigned int kGeolocationPollIntervalSeconds = 30 * 60; 54 55 const int64 kMillisecondsPerDay = Time::kMicrosecondsPerDay / 1000; 56 57 // Keys for the geolocation status dictionary in local state. 58 const char kLatitude[] = "latitude"; 59 const char kLongitude[] = "longitude"; 60 const char kAltitude[] = "altitude"; 61 const char kAccuracy[] = "accuracy"; 62 const char kAltitudeAccuracy[] = "altitude_accuracy"; 63 const char kHeading[] = "heading"; 64 const char kSpeed[] = "speed"; 65 const char kTimestamp[] = "timestamp"; 66 67 // Determine the day key (milliseconds since epoch for corresponding day in UTC) 68 // for a given |timestamp|. 69 int64 TimestampToDayKey(Time timestamp) { 70 Time::Exploded exploded; 71 timestamp.LocalMidnight().LocalExplode(&exploded); 72 return (Time::FromUTCExploded(exploded) - Time::UnixEpoch()).InMilliseconds(); 73 } 74 75 } // namespace 76 77 namespace policy { 78 79 DeviceStatusCollector::DeviceStatusCollector( 80 PrefService* local_state, 81 chromeos::system::StatisticsProvider* provider, 82 LocationUpdateRequester* location_update_requester) 83 : max_stored_past_activity_days_(kMaxStoredPastActivityDays), 84 max_stored_future_activity_days_(kMaxStoredFutureActivityDays), 85 local_state_(local_state), 86 last_idle_check_(Time()), 87 last_reported_day_(0), 88 duration_for_last_reported_day_(0), 89 geolocation_update_in_progress_(false), 90 statistics_provider_(provider), 91 report_version_info_(false), 92 report_activity_times_(false), 93 report_boot_mode_(false), 94 report_location_(false), 95 report_network_interfaces_(false), 96 report_users_(false), 97 weak_factory_(this) { 98 if (location_update_requester) 99 location_update_requester_ = *location_update_requester; 100 idle_poll_timer_.Start(FROM_HERE, 101 TimeDelta::FromSeconds(kIdlePollIntervalSeconds), 102 this, &DeviceStatusCollector::CheckIdleState); 103 104 cros_settings_ = chromeos::CrosSettings::Get(); 105 106 // Watch for changes to the individual policies that control what the status 107 // reports contain. 108 base::Closure callback = 109 base::Bind(&DeviceStatusCollector::UpdateReportingSettings, 110 base::Unretained(this)); 111 version_info_subscription_ = cros_settings_->AddSettingsObserver( 112 chromeos::kReportDeviceVersionInfo, callback); 113 activity_times_subscription_ = cros_settings_->AddSettingsObserver( 114 chromeos::kReportDeviceActivityTimes, callback); 115 boot_mode_subscription_ = cros_settings_->AddSettingsObserver( 116 chromeos::kReportDeviceBootMode, callback); 117 location_subscription_ = cros_settings_->AddSettingsObserver( 118 chromeos::kReportDeviceLocation, callback); 119 network_interfaces_subscription_ = cros_settings_->AddSettingsObserver( 120 chromeos::kReportDeviceNetworkInterfaces, callback); 121 users_subscription_ = cros_settings_->AddSettingsObserver( 122 chromeos::kReportDeviceUsers, callback); 123 124 // The last known location is persisted in local state. This makes location 125 // information available immediately upon startup and avoids the need to 126 // reacquire the location on every user session change or browser crash. 127 content::Geoposition position; 128 std::string timestamp_str; 129 int64 timestamp; 130 const base::DictionaryValue* location = 131 local_state_->GetDictionary(prefs::kDeviceLocation); 132 if (location->GetDouble(kLatitude, &position.latitude) && 133 location->GetDouble(kLongitude, &position.longitude) && 134 location->GetDouble(kAltitude, &position.altitude) && 135 location->GetDouble(kAccuracy, &position.accuracy) && 136 location->GetDouble(kAltitudeAccuracy, &position.altitude_accuracy) && 137 location->GetDouble(kHeading, &position.heading) && 138 location->GetDouble(kSpeed, &position.speed) && 139 location->GetString(kTimestamp, ×tamp_str) && 140 base::StringToInt64(timestamp_str, ×tamp)) { 141 position.timestamp = Time::FromInternalValue(timestamp); 142 position_ = position; 143 } 144 145 // Fetch the current values of the policies. 146 UpdateReportingSettings(); 147 148 // Get the the OS and firmware version info. 149 version_loader_.GetVersion( 150 VersionLoader::VERSION_FULL, 151 base::Bind(&DeviceStatusCollector::OnOSVersion, base::Unretained(this)), 152 &tracker_); 153 version_loader_.GetFirmware( 154 base::Bind(&DeviceStatusCollector::OnOSFirmware, base::Unretained(this)), 155 &tracker_); 156 } 157 158 DeviceStatusCollector::~DeviceStatusCollector() { 159 } 160 161 // static 162 void DeviceStatusCollector::RegisterPrefs(PrefRegistrySimple* registry) { 163 registry->RegisterDictionaryPref(prefs::kDeviceActivityTimes, 164 new base::DictionaryValue); 165 registry->RegisterDictionaryPref(prefs::kDeviceLocation, 166 new base::DictionaryValue); 167 } 168 169 void DeviceStatusCollector::CheckIdleState() { 170 CalculateIdleState(kIdleStateThresholdSeconds, 171 base::Bind(&DeviceStatusCollector::IdleStateCallback, 172 base::Unretained(this))); 173 } 174 175 void DeviceStatusCollector::UpdateReportingSettings() { 176 // Attempt to fetch the current value of the reporting settings. 177 // If trusted values are not available, register this function to be called 178 // back when they are available. 179 if (chromeos::CrosSettingsProvider::TRUSTED != 180 cros_settings_->PrepareTrustedValues( 181 base::Bind(&DeviceStatusCollector::UpdateReportingSettings, 182 weak_factory_.GetWeakPtr()))) { 183 return; 184 } 185 if (!cros_settings_->GetBoolean( 186 chromeos::kReportDeviceVersionInfo, &report_version_info_)) { 187 report_version_info_ = true; 188 } 189 if (!cros_settings_->GetBoolean( 190 chromeos::kReportDeviceActivityTimes, &report_activity_times_)) { 191 report_activity_times_ = true; 192 } 193 if (!cros_settings_->GetBoolean( 194 chromeos::kReportDeviceBootMode, &report_boot_mode_)) { 195 report_boot_mode_ = true; 196 } 197 if (!cros_settings_->GetBoolean( 198 chromeos::kReportDeviceLocation, &report_location_)) { 199 report_location_ = false; 200 } 201 if (!cros_settings_->GetBoolean( 202 chromeos::kReportDeviceNetworkInterfaces, &report_network_interfaces_)) { 203 report_network_interfaces_ = true; 204 } 205 if (!cros_settings_->GetBoolean( 206 chromeos::kReportDeviceUsers, &report_users_)) { 207 report_users_ = true; 208 } 209 210 if (report_location_) { 211 ScheduleGeolocationUpdateRequest(); 212 } else { 213 geolocation_update_timer_.Stop(); 214 position_ = content::Geoposition(); 215 local_state_->ClearPref(prefs::kDeviceLocation); 216 } 217 } 218 219 Time DeviceStatusCollector::GetCurrentTime() { 220 return Time::Now(); 221 } 222 223 // Remove all out-of-range activity times from the local store. 224 void DeviceStatusCollector::PruneStoredActivityPeriods(Time base_time) { 225 Time min_time = 226 base_time - TimeDelta::FromDays(max_stored_past_activity_days_); 227 Time max_time = 228 base_time + TimeDelta::FromDays(max_stored_future_activity_days_); 229 TrimStoredActivityPeriods(TimestampToDayKey(min_time), 0, 230 TimestampToDayKey(max_time)); 231 } 232 233 void DeviceStatusCollector::TrimStoredActivityPeriods(int64 min_day_key, 234 int min_day_trim_duration, 235 int64 max_day_key) { 236 const base::DictionaryValue* activity_times = 237 local_state_->GetDictionary(prefs::kDeviceActivityTimes); 238 239 scoped_ptr<base::DictionaryValue> copy(activity_times->DeepCopy()); 240 for (base::DictionaryValue::Iterator it(*activity_times); !it.IsAtEnd(); 241 it.Advance()) { 242 int64 timestamp; 243 if (base::StringToInt64(it.key(), ×tamp)) { 244 // Remove data that is too old, or too far in the future. 245 if (timestamp >= min_day_key && timestamp < max_day_key) { 246 if (timestamp == min_day_key) { 247 int new_activity_duration = 0; 248 if (it.value().GetAsInteger(&new_activity_duration)) { 249 new_activity_duration = 250 std::max(new_activity_duration - min_day_trim_duration, 0); 251 } 252 copy->SetInteger(it.key(), new_activity_duration); 253 } 254 continue; 255 } 256 } 257 // The entry is out of range or couldn't be parsed. Remove it. 258 copy->Remove(it.key(), NULL); 259 } 260 local_state_->Set(prefs::kDeviceActivityTimes, *copy); 261 } 262 263 void DeviceStatusCollector::AddActivePeriod(Time start, Time end) { 264 DCHECK(start < end); 265 266 // Maintain the list of active periods in a local_state pref. 267 DictionaryPrefUpdate update(local_state_, prefs::kDeviceActivityTimes); 268 base::DictionaryValue* activity_times = update.Get(); 269 270 // Assign the period to day buckets in local time. 271 Time midnight = start.LocalMidnight(); 272 while (midnight < end) { 273 midnight += TimeDelta::FromDays(1); 274 int64 activity = (std::min(end, midnight) - start).InMilliseconds(); 275 std::string day_key = base::Int64ToString(TimestampToDayKey(start)); 276 int previous_activity = 0; 277 activity_times->GetInteger(day_key, &previous_activity); 278 activity_times->SetInteger(day_key, previous_activity + activity); 279 start = midnight; 280 } 281 } 282 283 void DeviceStatusCollector::IdleStateCallback(IdleState state) { 284 // Do nothing if device activity reporting is disabled. 285 if (!report_activity_times_) 286 return; 287 288 Time now = GetCurrentTime(); 289 290 if (state == IDLE_STATE_ACTIVE) { 291 // If it's been too long since the last report, or if the activity is 292 // negative (which can happen when the clock changes), assume a single 293 // interval of activity. 294 int active_seconds = (now - last_idle_check_).InSeconds(); 295 if (active_seconds < 0 || 296 active_seconds >= static_cast<int>((2 * kIdlePollIntervalSeconds))) { 297 AddActivePeriod(now - TimeDelta::FromSeconds(kIdlePollIntervalSeconds), 298 now); 299 } else { 300 AddActivePeriod(last_idle_check_, now); 301 } 302 303 PruneStoredActivityPeriods(now); 304 } 305 last_idle_check_ = now; 306 } 307 308 void DeviceStatusCollector::GetActivityTimes( 309 em::DeviceStatusReportRequest* request) { 310 DictionaryPrefUpdate update(local_state_, prefs::kDeviceActivityTimes); 311 base::DictionaryValue* activity_times = update.Get(); 312 313 for (base::DictionaryValue::Iterator it(*activity_times); !it.IsAtEnd(); 314 it.Advance()) { 315 int64 start_timestamp; 316 int activity_milliseconds; 317 if (base::StringToInt64(it.key(), &start_timestamp) && 318 it.value().GetAsInteger(&activity_milliseconds)) { 319 // This is correct even when there are leap seconds, because when a leap 320 // second occurs, two consecutive seconds have the same timestamp. 321 int64 end_timestamp = start_timestamp + kMillisecondsPerDay; 322 323 em::ActiveTimePeriod* active_period = request->add_active_period(); 324 em::TimePeriod* period = active_period->mutable_time_period(); 325 period->set_start_timestamp(start_timestamp); 326 period->set_end_timestamp(end_timestamp); 327 active_period->set_active_duration(activity_milliseconds); 328 if (start_timestamp >= last_reported_day_) { 329 last_reported_day_ = start_timestamp; 330 duration_for_last_reported_day_ = activity_milliseconds; 331 } 332 } else { 333 NOTREACHED(); 334 } 335 } 336 } 337 338 void DeviceStatusCollector::GetVersionInfo( 339 em::DeviceStatusReportRequest* request) { 340 chrome::VersionInfo version_info; 341 request->set_browser_version(version_info.Version()); 342 request->set_os_version(os_version_); 343 request->set_firmware_version(firmware_version_); 344 } 345 346 void DeviceStatusCollector::GetBootMode( 347 em::DeviceStatusReportRequest* request) { 348 std::string dev_switch_mode; 349 if (statistics_provider_->GetMachineStatistic( 350 chromeos::system::kDevSwitchBootMode, &dev_switch_mode)) { 351 if (dev_switch_mode == "1") 352 request->set_boot_mode("Dev"); 353 else if (dev_switch_mode == "0") 354 request->set_boot_mode("Verified"); 355 } 356 } 357 358 void DeviceStatusCollector::GetLocation( 359 em::DeviceStatusReportRequest* request) { 360 em::DeviceLocation* location = request->mutable_device_location(); 361 if (!position_.Validate()) { 362 location->set_error_code( 363 em::DeviceLocation::ERROR_CODE_POSITION_UNAVAILABLE); 364 location->set_error_message(position_.error_message); 365 } else { 366 location->set_latitude(position_.latitude); 367 location->set_longitude(position_.longitude); 368 location->set_accuracy(position_.accuracy); 369 location->set_timestamp( 370 (position_.timestamp - Time::UnixEpoch()).InMilliseconds()); 371 // Lowest point on land is at approximately -400 meters. 372 if (position_.altitude > -10000.) 373 location->set_altitude(position_.altitude); 374 if (position_.altitude_accuracy >= 0.) 375 location->set_altitude_accuracy(position_.altitude_accuracy); 376 if (position_.heading >= 0. && position_.heading <= 360) 377 location->set_heading(position_.heading); 378 if (position_.speed >= 0.) 379 location->set_speed(position_.speed); 380 location->set_error_code(em::DeviceLocation::ERROR_CODE_NONE); 381 } 382 } 383 384 void DeviceStatusCollector::GetNetworkInterfaces( 385 em::DeviceStatusReportRequest* request) { 386 // Maps flimflam device type strings to proto enum constants. 387 static const struct { 388 const char* type_string; 389 em::NetworkInterface::NetworkDeviceType type_constant; 390 } kDeviceTypeMap[] = { 391 { shill::kTypeEthernet, em::NetworkInterface::TYPE_ETHERNET, }, 392 { shill::kTypeWifi, em::NetworkInterface::TYPE_WIFI, }, 393 { shill::kTypeWimax, em::NetworkInterface::TYPE_WIMAX, }, 394 { shill::kTypeBluetooth, em::NetworkInterface::TYPE_BLUETOOTH, }, 395 { shill::kTypeCellular, em::NetworkInterface::TYPE_CELLULAR, }, 396 }; 397 398 chromeos::NetworkStateHandler::DeviceStateList device_list; 399 chromeos::NetworkHandler::Get()->network_state_handler()->GetDeviceList( 400 &device_list); 401 402 chromeos::NetworkStateHandler::DeviceStateList::const_iterator device; 403 for (device = device_list.begin(); device != device_list.end(); ++device) { 404 // Determine the type enum constant for |device|. 405 size_t type_idx = 0; 406 for (; type_idx < ARRAYSIZE_UNSAFE(kDeviceTypeMap); ++type_idx) { 407 if ((*device)->type() == kDeviceTypeMap[type_idx].type_string) 408 break; 409 } 410 411 // If the type isn't in |kDeviceTypeMap|, the interface is not relevant for 412 // reporting. This filters out VPN devices. 413 if (type_idx >= ARRAYSIZE_UNSAFE(kDeviceTypeMap)) 414 continue; 415 416 em::NetworkInterface* interface = request->add_network_interface(); 417 interface->set_type(kDeviceTypeMap[type_idx].type_constant); 418 if (!(*device)->mac_address().empty()) 419 interface->set_mac_address((*device)->mac_address()); 420 if (!(*device)->meid().empty()) 421 interface->set_meid((*device)->meid()); 422 if (!(*device)->imei().empty()) 423 interface->set_imei((*device)->imei()); 424 } 425 } 426 427 void DeviceStatusCollector::GetUsers(em::DeviceStatusReportRequest* request) { 428 policy::BrowserPolicyConnectorChromeOS* connector = 429 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 430 const user_manager::UserList& users = 431 user_manager::UserManager::Get()->GetUsers(); 432 user_manager::UserList::const_iterator user; 433 for (user = users.begin(); user != users.end(); ++user) { 434 // Only regular users are reported. 435 if ((*user)->GetType() != user_manager::USER_TYPE_REGULAR) 436 continue; 437 438 em::DeviceUser* device_user = request->add_user(); 439 const std::string& email = (*user)->email(); 440 if (connector->GetUserAffiliation(email) == USER_AFFILIATION_MANAGED) { 441 device_user->set_type(em::DeviceUser::USER_TYPE_MANAGED); 442 device_user->set_email(email); 443 } else { 444 device_user->set_type(em::DeviceUser::USER_TYPE_UNMANAGED); 445 // Do not report the email address of unmanaged users. 446 } 447 } 448 } 449 450 void DeviceStatusCollector::GetStatus(em::DeviceStatusReportRequest* request) { 451 // TODO(mnissler): Remove once the old cloud policy stack is retired. The old 452 // stack doesn't support reporting successful submissions back to here, so 453 // just assume whatever ends up in |request| gets submitted successfully. 454 GetDeviceStatus(request); 455 OnSubmittedSuccessfully(); 456 } 457 458 bool DeviceStatusCollector::GetDeviceStatus( 459 em::DeviceStatusReportRequest* status) { 460 if (report_activity_times_) 461 GetActivityTimes(status); 462 463 if (report_version_info_) 464 GetVersionInfo(status); 465 466 if (report_boot_mode_) 467 GetBootMode(status); 468 469 if (report_location_) 470 GetLocation(status); 471 472 if (report_network_interfaces_) 473 GetNetworkInterfaces(status); 474 475 if (report_users_) { 476 GetUsers(status); 477 } 478 479 return true; 480 } 481 482 bool DeviceStatusCollector::GetSessionStatus( 483 em::SessionStatusReportRequest* status) { 484 return false; 485 } 486 487 void DeviceStatusCollector::OnSubmittedSuccessfully() { 488 TrimStoredActivityPeriods(last_reported_day_, duration_for_last_reported_day_, 489 std::numeric_limits<int64>::max()); 490 } 491 492 void DeviceStatusCollector::OnOSVersion(const std::string& version) { 493 os_version_ = version; 494 } 495 496 void DeviceStatusCollector::OnOSFirmware(const std::string& version) { 497 firmware_version_ = version; 498 } 499 500 void DeviceStatusCollector::ScheduleGeolocationUpdateRequest() { 501 if (geolocation_update_timer_.IsRunning() || geolocation_update_in_progress_) 502 return; 503 504 if (position_.Validate()) { 505 TimeDelta elapsed = GetCurrentTime() - position_.timestamp; 506 TimeDelta interval = 507 TimeDelta::FromSeconds(kGeolocationPollIntervalSeconds); 508 if (elapsed <= interval) { 509 geolocation_update_timer_.Start( 510 FROM_HERE, 511 interval - elapsed, 512 this, 513 &DeviceStatusCollector::ScheduleGeolocationUpdateRequest); 514 return; 515 } 516 } 517 518 geolocation_update_in_progress_ = true; 519 if (location_update_requester_.is_null()) { 520 geolocation_subscription_ = content::GeolocationProvider::GetInstance()-> 521 AddLocationUpdateCallback( 522 base::Bind(&DeviceStatusCollector::ReceiveGeolocationUpdate, 523 weak_factory_.GetWeakPtr()), 524 true); 525 } else { 526 location_update_requester_.Run(base::Bind( 527 &DeviceStatusCollector::ReceiveGeolocationUpdate, 528 weak_factory_.GetWeakPtr())); 529 } 530 } 531 532 void DeviceStatusCollector::ReceiveGeolocationUpdate( 533 const content::Geoposition& position) { 534 geolocation_update_in_progress_ = false; 535 536 // Ignore update if device location reporting has since been disabled. 537 if (!report_location_) 538 return; 539 540 if (position.Validate()) { 541 position_ = position; 542 base::DictionaryValue location; 543 location.SetDouble(kLatitude, position.latitude); 544 location.SetDouble(kLongitude, position.longitude); 545 location.SetDouble(kAltitude, position.altitude); 546 location.SetDouble(kAccuracy, position.accuracy); 547 location.SetDouble(kAltitudeAccuracy, position.altitude_accuracy); 548 location.SetDouble(kHeading, position.heading); 549 location.SetDouble(kSpeed, position.speed); 550 location.SetString(kTimestamp, 551 base::Int64ToString(position.timestamp.ToInternalValue())); 552 local_state_->Set(prefs::kDeviceLocation, location); 553 } 554 555 ScheduleGeolocationUpdateRequest(); 556 } 557 558 } // namespace policy 559