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