| Index: chrome/browser/policy/device_status_collector.cc
|
| diff --git a/chrome/browser/policy/device_status_collector.cc b/chrome/browser/policy/device_status_collector.cc
|
| index 5a1be4a47e71c915d8cacb835f309389be5cc942..cb547cf5aade4cea83e25b3d1ff74c56b962ca2a 100644
|
| --- a/chrome/browser/policy/device_status_collector.cc
|
| +++ b/chrome/browser/policy/device_status_collector.cc
|
| @@ -5,8 +5,12 @@
|
| #include "chrome/browser/policy/device_status_collector.h"
|
|
|
| #include "base/bind.h"
|
| -#include "base/callback.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/location.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| #include "base/string_number_conversions.h"
|
| +#include "base/values.h"
|
| #include "chrome/browser/chromeos/cros_settings.h"
|
| #include "chrome/browser/chromeos/cros_settings_names.h"
|
| #include "chrome/browser/chromeos/system/statistics_provider.h"
|
| @@ -16,6 +20,8 @@
|
| #include "chrome/common/chrome_notification_types.h"
|
| #include "chrome/common/chrome_version_info.h"
|
| #include "chrome/common/pref_names.h"
|
| +#include "content/public/browser/notification_details.h"
|
| +#include "content/public/browser/notification_source.h"
|
|
|
| using base::Time;
|
| using base::TimeDelta;
|
| @@ -33,10 +39,29 @@ const unsigned int kMaxStoredPastActivityDays = 30;
|
| // How many days in the future to store active periods for.
|
| const unsigned int kMaxStoredFutureActivityDays = 2;
|
|
|
| +// How often, in seconds, to update the device location.
|
| +const unsigned int kGeolocationPollIntervalSeconds = 30 * 60;
|
| +
|
| const int64 kMillisecondsPerDay = Time::kMicrosecondsPerDay / 1000;
|
|
|
| +const char kLatitude[] = "latitude";
|
| +
|
| +const char kLongitude[] = "longitude";
|
| +
|
| +const char kAltitude[] = "altitude";
|
| +
|
| +const char kAccuracy[] = "accuracy";
|
| +
|
| +const char kAltitudeAccuracy[] = "altitude_accuracy";
|
| +
|
| +const char kHeading[] = "heading";
|
| +
|
| +const char kSpeed[] = "speed";
|
| +
|
| +const char kTimestamp[] = "timestamp";
|
| +
|
| // Record device activity for the specified day into the given dictionary.
|
| -void AddDeviceActivity(DictionaryValue* activity_times,
|
| +void AddDeviceActivity(base::DictionaryValue* activity_times,
|
| Time day_midnight,
|
| TimeDelta activity) {
|
| DCHECK(activity.InMilliseconds() < kMillisecondsPerDay);
|
| @@ -55,18 +80,25 @@ namespace policy {
|
|
|
| DeviceStatusCollector::DeviceStatusCollector(
|
| PrefService* local_state,
|
| - chromeos::system::StatisticsProvider* provider)
|
| + chromeos::system::StatisticsProvider* provider,
|
| + LocationUpdateRequester location_update_requester)
|
| : max_stored_past_activity_days_(kMaxStoredPastActivityDays),
|
| max_stored_future_activity_days_(kMaxStoredFutureActivityDays),
|
| local_state_(local_state),
|
| last_idle_check_(Time()),
|
| + geolocation_update_in_progress_(false),
|
| statistics_provider_(provider),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
|
| + location_update_requester_(location_update_requester),
|
| report_version_info_(false),
|
| report_activity_times_(false),
|
| - report_boot_mode_(false) {
|
| - timer_.Start(FROM_HERE,
|
| - TimeDelta::FromSeconds(kPollIntervalSeconds),
|
| - this, &DeviceStatusCollector::CheckIdleState);
|
| + report_boot_mode_(false),
|
| + report_location_(false) {
|
| + if (!location_update_requester_)
|
| + location_update_requester_ = &content::RequestLocationUpdate;
|
| + idle_poll_timer_.Start(FROM_HERE,
|
| + TimeDelta::FromSeconds(kIdlePollIntervalSeconds),
|
| + this, &DeviceStatusCollector::CheckIdleState);
|
|
|
| cros_settings_ = chromeos::CrosSettings::Get();
|
|
|
| @@ -76,6 +108,28 @@ DeviceStatusCollector::DeviceStatusCollector(
|
| cros_settings_->AddSettingsObserver(chromeos::kReportDeviceActivityTimes,
|
| this);
|
| cros_settings_->AddSettingsObserver(chromeos::kReportDeviceBootMode, this);
|
| + cros_settings_->AddSettingsObserver(chromeos::kReportDeviceLocation, this);
|
| +
|
| + // The last known location is persisted in local state. This makes location
|
| + // information available immediately upon startup and avoids the need to
|
| + // reacquire the location on every user session change or browser crash.
|
| + content::Geoposition position;
|
| + std::string timestamp_str;
|
| + int64 timestamp;
|
| + const base::DictionaryValue* location =
|
| + local_state_->GetDictionary(prefs::kDeviceLocation);
|
| + if (location->GetDouble(kLatitude, &position.latitude) &&
|
| + location->GetDouble(kLongitude, &position.longitude) &&
|
| + location->GetDouble(kAltitude, &position.altitude) &&
|
| + location->GetDouble(kAccuracy, &position.accuracy) &&
|
| + location->GetDouble(kAltitudeAccuracy, &position.altitude_accuracy) &&
|
| + location->GetDouble(kHeading, &position.heading) &&
|
| + location->GetDouble(kSpeed, &position.speed) &&
|
| + location->GetString(kTimestamp, ×tamp_str) &&
|
| + base::StringToInt64(timestamp_str, ×tamp)) {
|
| + position.timestamp = Time::FromInternalValue(timestamp);
|
| + position_ = position;
|
| + }
|
|
|
| // Fetch the current values of the policies.
|
| UpdateReportingSettings();
|
| @@ -96,12 +150,15 @@ DeviceStatusCollector::~DeviceStatusCollector() {
|
| cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceActivityTimes,
|
| this);
|
| cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceBootMode, this);
|
| + cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceLocation, this);
|
| }
|
|
|
| // static
|
| void DeviceStatusCollector::RegisterPrefs(PrefService* local_state) {
|
| local_state->RegisterDictionaryPref(prefs::kDeviceActivityTimes,
|
| - new DictionaryValue);
|
| + new base::DictionaryValue);
|
| + local_state->RegisterDictionaryPref(prefs::kDeviceLocation,
|
| + new base::DictionaryValue);
|
| }
|
|
|
| void DeviceStatusCollector::CheckIdleState() {
|
| @@ -125,6 +182,16 @@ void DeviceStatusCollector::UpdateReportingSettings() {
|
| chromeos::kReportDeviceActivityTimes, &report_activity_times_);
|
| cros_settings_->GetBoolean(
|
| chromeos::kReportDeviceBootMode, &report_boot_mode_);
|
| + cros_settings_->GetBoolean(
|
| + chromeos::kReportDeviceLocation, &report_location_);
|
| +
|
| + if (report_location_) {
|
| + ScheduleGeolocationUpdateRequest();
|
| + } else {
|
| + geolocation_update_timer_.Stop();
|
| + position_ = content::Geoposition();
|
| + local_state_->ClearPref(prefs::kDeviceLocation);
|
| + }
|
| }
|
|
|
| Time DeviceStatusCollector::GetCurrentTime() {
|
| @@ -133,7 +200,7 @@ Time DeviceStatusCollector::GetCurrentTime() {
|
|
|
| // Remove all out-of-range activity times from the local store.
|
| void DeviceStatusCollector::PruneStoredActivityPeriods(Time base_time) {
|
| - const DictionaryValue* activity_times =
|
| + const base::DictionaryValue* activity_times =
|
| local_state_->GetDictionary(prefs::kDeviceActivityTimes);
|
| if (activity_times->size() <=
|
| max_stored_past_activity_days_ + max_stored_future_activity_days_)
|
| @@ -145,8 +212,8 @@ void DeviceStatusCollector::PruneStoredActivityPeriods(Time base_time) {
|
| base_time + TimeDelta::FromDays(max_stored_future_activity_days_);
|
| const Time epoch = Time::UnixEpoch();
|
|
|
| - scoped_ptr<DictionaryValue> copy(activity_times->DeepCopy());
|
| - for (DictionaryValue::key_iterator it = activity_times->begin_keys();
|
| + scoped_ptr<base::DictionaryValue> copy(activity_times->DeepCopy());
|
| + for (base::DictionaryValue::key_iterator it = activity_times->begin_keys();
|
| it != activity_times->end_keys(); ++it) {
|
| int64 timestamp;
|
|
|
| @@ -167,7 +234,7 @@ void DeviceStatusCollector::AddActivePeriod(Time start, Time end) {
|
|
|
| // Maintain the list of active periods in a local_state pref.
|
| DictionaryPrefUpdate update(local_state_, prefs::kDeviceActivityTimes);
|
| - DictionaryValue* activity_times = update.Get();
|
| + base::DictionaryValue* activity_times = update.Get();
|
|
|
| Time midnight = end.LocalMidnight();
|
|
|
| @@ -201,8 +268,9 @@ void DeviceStatusCollector::IdleStateCallback(IdleState state) {
|
| // interval of activity.
|
| int active_seconds = (now - last_idle_check_).InSeconds();
|
| if (active_seconds < 0 ||
|
| - active_seconds >= static_cast<int>((2 * kPollIntervalSeconds)))
|
| - AddActivePeriod(now - TimeDelta::FromSeconds(kPollIntervalSeconds), now);
|
| + active_seconds >= static_cast<int>((2 * kIdlePollIntervalSeconds)))
|
| + AddActivePeriod(now - TimeDelta::FromSeconds(kIdlePollIntervalSeconds),
|
| + now);
|
| else
|
| AddActivePeriod(last_idle_check_, now);
|
|
|
| @@ -214,9 +282,9 @@ void DeviceStatusCollector::IdleStateCallback(IdleState state) {
|
| void DeviceStatusCollector::GetActivityTimes(
|
| em::DeviceStatusReportRequest* request) {
|
| DictionaryPrefUpdate update(local_state_, prefs::kDeviceActivityTimes);
|
| - DictionaryValue* activity_times = update.Get();
|
| + base::DictionaryValue* activity_times = update.Get();
|
|
|
| - for (DictionaryValue::key_iterator it = activity_times->begin_keys();
|
| + for (base::DictionaryValue::key_iterator it = activity_times->begin_keys();
|
| it != activity_times->end_keys(); ++it) {
|
| int64 start_timestamp;
|
| int activity_milliseconds;
|
| @@ -258,6 +326,32 @@ void DeviceStatusCollector::GetBootMode(
|
| }
|
| }
|
|
|
| +void DeviceStatusCollector::GetLocation(
|
| + em::DeviceStatusReportRequest* request) {
|
| + em::DeviceLocation* location = request->mutable_device_location();
|
| + if (!position_.Validate()) {
|
| + location->set_error_code(
|
| + em::DeviceLocation::ERROR_CODE_POSITION_UNAVAILABLE);
|
| + location->set_error_message(position_.error_message);
|
| + } else {
|
| + location->set_latitude(position_.latitude);
|
| + location->set_longitude(position_.longitude);
|
| + location->set_accuracy(position_.accuracy);
|
| + location->set_timestamp(
|
| + (position_.timestamp - Time::UnixEpoch()).InMilliseconds());
|
| + // Lowest point on land is at approximately -400 meters.
|
| + if (position_.altitude > -10000.)
|
| + location->set_altitude(position_.altitude);
|
| + if (position_.altitude_accuracy >= 0.)
|
| + location->set_altitude_accuracy(position_.altitude_accuracy);
|
| + if (position_.heading >= 0. && position_.heading <= 360)
|
| + location->set_heading(position_.heading);
|
| + if (position_.speed >= 0.)
|
| + location->set_speed(position_.speed);
|
| + location->set_error_code(em::DeviceLocation::ERROR_CODE_NONE);
|
| + }
|
| +}
|
| +
|
| void DeviceStatusCollector::GetStatus(em::DeviceStatusReportRequest* request) {
|
| if (report_activity_times_)
|
| GetActivityTimes(request);
|
| @@ -267,6 +361,9 @@ void DeviceStatusCollector::GetStatus(em::DeviceStatusReportRequest* request) {
|
|
|
| if (report_boot_mode_)
|
| GetBootMode(request);
|
| +
|
| + if (report_location_)
|
| + GetLocation(request);
|
| }
|
|
|
| void DeviceStatusCollector::OnOSVersion(VersionLoader::Handle handle,
|
| @@ -289,4 +386,59 @@ void DeviceStatusCollector::Observe(
|
| NOTREACHED();
|
| }
|
|
|
| +void DeviceStatusCollector::ScheduleGeolocationUpdateRequest() {
|
| + if (geolocation_update_timer_.IsRunning() || geolocation_update_in_progress_)
|
| + return;
|
| +
|
| + if (position_.Validate()) {
|
| + TimeDelta elapsed = Time::Now() - position_.timestamp;
|
| + TimeDelta interval =
|
| + TimeDelta::FromSeconds(kGeolocationPollIntervalSeconds);
|
| + if (elapsed > interval) {
|
| + geolocation_update_in_progress_ = true;
|
| + location_update_requester_(base::Bind(
|
| + &DeviceStatusCollector::ReceiveGeolocationUpdate,
|
| + weak_factory_.GetWeakPtr()));
|
| + } else {
|
| + geolocation_update_timer_.Start(
|
| + FROM_HERE,
|
| + interval - elapsed,
|
| + this,
|
| + &DeviceStatusCollector::ScheduleGeolocationUpdateRequest);
|
| + }
|
| + } else {
|
| + geolocation_update_in_progress_ = true;
|
| + location_update_requester_(base::Bind(
|
| + &DeviceStatusCollector::ReceiveGeolocationUpdate,
|
| + weak_factory_.GetWeakPtr()));
|
| +
|
| + }
|
| +}
|
| +
|
| +void DeviceStatusCollector::ReceiveGeolocationUpdate(
|
| + const content::Geoposition& position) {
|
| + geolocation_update_in_progress_ = false;
|
| +
|
| + // Ignore update if device location reporting has since been disabled.
|
| + if (!report_location_)
|
| + return;
|
| +
|
| + if (position.Validate()) {
|
| + position_ = position;
|
| + base::DictionaryValue location;
|
| + location.SetDouble(kLatitude, position.latitude);
|
| + location.SetDouble(kLongitude, position.longitude);
|
| + location.SetDouble(kAltitude, position.altitude);
|
| + location.SetDouble(kAccuracy, position.accuracy);
|
| + location.SetDouble(kAltitudeAccuracy, position.altitude_accuracy);
|
| + location.SetDouble(kHeading, position.heading);
|
| + location.SetDouble(kSpeed, position.speed);
|
| + location.SetString(kTimestamp,
|
| + base::Int64ToString(position.timestamp.ToInternalValue()));
|
| + local_state_->Set(prefs::kDeviceLocation, location);
|
| + }
|
| +
|
| + ScheduleGeolocationUpdateRequest();
|
| +}
|
| +
|
| } // namespace policy
|
|
|