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

Unified Diff: chrome/browser/policy/device_status_collector.cc

Issue 10103029: Add device location reporting (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 8 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 side-by-side diff with in-line comments
Download patch
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..f7dc3b640f7f07047d45405b68ee45194e1e9e84 100644
--- a/chrome/browser/policy/device_status_collector.cc
+++ b/chrome/browser/policy/device_status_collector.cc
@@ -16,6 +16,8 @@
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/pref_names.h"
+#include "content/browser/geolocation/geolocation_provider.h"
+#include "content/public/browser/browser_thread.h"
using base::Time;
using base::TimeDelta;
@@ -53,6 +55,210 @@ void AddDeviceActivity(DictionaryValue* activity_times,
namespace policy {
+// Helper class for retrieving the device's geographic location.
+class DeviceStatusLocationHelper : public GeolocationObserver {
Joao da Silva 2012/04/20 09:49:57 I'd move this one to its own file.
bartfab (slow) 2012/04/20 14:10:15 Done.
+ public:
+ explicit DeviceStatusLocationHelper(PrefService* local_state);
+ virtual ~DeviceStatusLocationHelper();
+ void Destruct();
+
+ const Geoposition& GetPosition() const;
+
+ static void RegisterPrefs(PrefService* local_state);
+
+ virtual void OnLocationUpdate(const Geoposition& position);
Joao da Silva 2012/04/20 09:49:57 OVERRIDE
bartfab (slow) 2012/04/20 14:10:15 Done.
+
+ void SetGeolocationProviderForTest(GeolocationProvider* provider);
+
+ static const unsigned int kPollIntervalSeconds = 1800;
+
+ private:
+ void Init(const Geoposition& position);
+ void DestructInternal();
+
+ void ScheduleUpdate(const Geoposition& position);
+
+ void StartObserving();
+ void StopObserving();
+
+ void ReceiveUpdate(const Geoposition& position);
+
+ // Used by UI thread only
+ PrefService* local_state_;
+ Geoposition position_;
+
+ // Used by IO thread only
+ base::OneShotTimer<DeviceStatusLocationHelper> *timer_;
+ GeolocationProvider* provider_;
+ bool observing_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceStatusLocationHelper);
+};
+
+DeviceStatusLocationHelper::DeviceStatusLocationHelper(
+ PrefService* local_state)
+ : local_state_(local_state),
+ timer_(NULL),
+ provider_(NULL),
+ observing_(false) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ Geoposition position;
+ std::string timestamp_str;
+ int64 timestamp;
+ const base::DictionaryValue* location =
+ local_state_->GetDictionary(prefs::kDeviceLocation);
+ if (location->GetDouble("latitude", &position.latitude) &&
+ location->GetDouble("longitude", &position.longitude) &&
+ location->GetDouble("altitude", &position.altitude) &&
+ location->GetDouble("accuracy", &position.accuracy) &&
+ location->GetDouble("altitude_accuracy",
+ &position.altitude_accuracy) &&
+ location->GetDouble("heading", &position.heading) &&
+ location->GetDouble("speed", &position.speed) &&
+ location->GetString("timestamp", &timestamp_str) &&
+ base::StringToInt64(timestamp_str, &timestamp)) {
+ position.timestamp = base::Time::FromInternalValue(timestamp);
Joao da Silva 2012/04/20 09:49:57 Nit: base::Time -> Time
bartfab (slow) 2012/04/20 14:10:15 It moved to its own .cc file without "using base::
+ position_ = position;
+ }
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&DeviceStatusLocationHelper::Init,
+ base::Unretained(this),
+ position_));
+}
+
+DeviceStatusLocationHelper::~DeviceStatusLocationHelper() {
+ // Do not call the destructor directly. Call Destruct() instead.
+ // The destructor is only public so that the DeleteSoon task can call it.
Joao da Silva 2012/04/20 09:49:57 Make the dtor private, and add friend class base:
bartfab (slow) 2012/04/20 14:10:15 Done.
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(local_state_ == NULL);
+ DCHECK(timer_ == NULL);
+}
+
+void DeviceStatusLocationHelper::Destruct() {
+ // This class has a specific shutdown sequence that ensures all classes it
+ // interfaces with are notified on the appropriate threads and any tasks
+ // posted to it are processed before destrucion.
Joao da Silva 2012/04/20 09:49:57 *destruction
bartfab (slow) 2012/04/20 14:10:15 Done.
+ //
+ // The shutdown sequence is initiated by calling Destruct() on the UI thread:
+ //
+ // 1. Destruct() makes the UI thread ignore any further updates it receives,
+ // then posts DestructInner() to the IO thread.
+ // 2. DestructInner() reaches the IO thread after any updates queued up for it
Joao da Silva 2012/04/20 09:49:57 In these 2 lines: DestructInner -> DestructInterna
bartfab (slow) 2012/04/20 14:10:15 Done.
+ // have been processed. This function destroys the poll timer and detaches
+ // from the GeolocationProvider so that no further updates can be received
+ // by the IO thread. Then, it posts DeleteSoon() back to the UI thread.
+ // 3. DeleteSoon() reaches the UI thread after any updates queued for it have
+ // been processed. At this point, there are no more tasks queued up for
+ // either of the threads and it is safe for the object to be deleted.
+ // 4. ~DeviceStatusLocationHelper() is run by DeleteSoon() and the object RIP.
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ local_state_ = NULL;
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&DeviceStatusLocationHelper::DestructInternal,
+ base::Unretained(this)));
+}
+
+const Geoposition& DeviceStatusLocationHelper::GetPosition() const {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ return position_;
+}
+
+// static
+void DeviceStatusLocationHelper::RegisterPrefs(PrefService* local_state) {
+ local_state->RegisterDictionaryPref(prefs::kDeviceLocation,
+ new DictionaryValue);
+}
+
+void DeviceStatusLocationHelper::OnLocationUpdate(const Geoposition& position) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ if (!position.IsValidFix())
+ return;
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&DeviceStatusLocationHelper::ReceiveUpdate,
+ base::Unretained(this), position));
+ StopObserving();
+ ScheduleUpdate(position);
+}
+
+void DeviceStatusLocationHelper::SetGeolocationProviderForTest(
+ GeolocationProvider* provider) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ DCHECK(!provider_);
+ provider_ = provider;
+}
+
+void DeviceStatusLocationHelper::Init(const Geoposition& position) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ if (!provider_)
+ provider_ = GeolocationProvider::GetInstance();
+ timer_ = new base::OneShotTimer<DeviceStatusLocationHelper>();
+ provider_->OnPermissionGranted();
Joao da Silva 2012/04/20 09:49:57 Doesn't this need a GURL?
bartfab (slow) 2012/04/20 14:10:15 The GURL parameter was not actually being used for
Joao da Silva 2012/04/20 14:21:09 I see, thanks for the clarification.
+ ScheduleUpdate(position);
+}
+
+void DeviceStatusLocationHelper::DestructInternal() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ delete timer_;
+ timer_ = 0;
+ StopObserving();
+ content::BrowserThread::DeleteSoon(content::BrowserThread::UI,
+ FROM_HERE,
+ this);
+}
+
+void DeviceStatusLocationHelper::ScheduleUpdate(const Geoposition& position) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ if (position.IsValidFix()) {
+ TimeDelta elapsed = Time::Now() - position.timestamp;
+ TimeDelta interval = TimeDelta::FromSeconds(kPollIntervalSeconds);
+ if (elapsed > interval)
+ StartObserving();
+ timer_->Start(FROM_HERE, interval - elapsed, this,
+ &DeviceStatusLocationHelper::StartObserving);
Joao da Silva 2012/04/20 09:49:57 Shouldn't this be in an else block here, so that i
bartfab (slow) 2012/04/20 14:10:15 Done.
+ } else {
+ StartObserving();
+ }
+}
+
+void DeviceStatusLocationHelper::StartObserving() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ timer_->Stop();
+ provider_->AddObserver(this, GeolocationObserverOptions(true));
+ observing_ = true;
+}
+
+void DeviceStatusLocationHelper::StopObserving() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ if (!observing_)
+ return;
+ provider_->RemoveObserver(this);
+ observing_ = false;
+}
+
+void DeviceStatusLocationHelper::ReceiveUpdate(const Geoposition& position) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (!local_state_)
+ return;
+ position_ = position;
+ DictionaryValue location;
+ location.SetDouble("latitude", position.latitude);
+ location.SetDouble("longitude", position.longitude);
+ location.SetDouble("altitude", position.altitude);
+ location.SetDouble("accuracy", position.accuracy);
+ location.SetDouble("altitude_accuracy", position.altitude_accuracy);
+ location.SetDouble("heading", position.heading);
+ location.SetDouble("speed", position.speed);
+ location.SetString("timestamp",
+ base::Int64ToString(position.timestamp.ToInternalValue()));
+ local_state_->Set(prefs::kDeviceLocation, location);
+}
+
DeviceStatusCollector::DeviceStatusCollector(
PrefService* local_state,
chromeos::system::StatisticsProvider* provider)
@@ -61,9 +267,12 @@ DeviceStatusCollector::DeviceStatusCollector(
local_state_(local_state),
last_idle_check_(Time()),
statistics_provider_(provider),
+ geolocation_provider_for_test_(NULL),
+ location_helper_(NULL),
report_version_info_(false),
report_activity_times_(false),
- report_boot_mode_(false) {
+ report_boot_mode_(false),
+ report_location_(false) {
timer_.Start(FROM_HERE,
TimeDelta::FromSeconds(kPollIntervalSeconds),
this, &DeviceStatusCollector::CheckIdleState);
@@ -76,6 +285,7 @@ DeviceStatusCollector::DeviceStatusCollector(
cros_settings_->AddSettingsObserver(chromeos::kReportDeviceActivityTimes,
this);
cros_settings_->AddSettingsObserver(chromeos::kReportDeviceBootMode, this);
+ cros_settings_->AddSettingsObserver(chromeos::kReportDeviceLocation, this);
// Fetch the current values of the policies.
UpdateReportingSettings();
@@ -96,12 +306,17 @@ DeviceStatusCollector::~DeviceStatusCollector() {
cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceActivityTimes,
this);
cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceBootMode, this);
+ cros_settings_->RemoveSettingsObserver(chromeos::kReportDeviceLocation, this);
+
+ if (location_helper_)
+ location_helper_->Destruct();
}
// static
void DeviceStatusCollector::RegisterPrefs(PrefService* local_state) {
local_state->RegisterDictionaryPref(prefs::kDeviceActivityTimes,
new DictionaryValue);
+ DeviceStatusLocationHelper::RegisterPrefs(local_state);
}
void DeviceStatusCollector::CheckIdleState() {
@@ -110,6 +325,13 @@ void DeviceStatusCollector::CheckIdleState() {
base::Unretained(this)));
}
+void DeviceStatusCollector::SetGeolocationProviderForTest(
+ GeolocationProvider* provider) {
+ geolocation_provider_for_test_ = provider;
+ if (location_helper_)
+ location_helper_->SetGeolocationProviderForTest(provider);
+}
+
void DeviceStatusCollector::UpdateReportingSettings() {
// Attempt to fetch the current value of the reporting settings.
// If trusted values are not available, register this function to be called
@@ -125,6 +347,23 @@ 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_) {
+ if (!location_helper_) {
+ location_helper_ = new DeviceStatusLocationHelper(local_state_);
+ if (geolocation_provider_for_test_)
Joao da Silva 2012/04/20 09:49:57 Braces around the block when it spans more than 1
bartfab (slow) 2012/04/20 14:10:15 Done.
+ location_helper_->SetGeolocationProviderForTest(
+ geolocation_provider_for_test_);
+ }
+ } else {
+ if (location_helper_) {
+ location_helper_->Destruct();
+ location_helper_ = NULL;
+ }
+ local_state_->ClearPref(prefs::kDeviceLocation);
+ }
}
Time DeviceStatusCollector::GetCurrentTime() {
@@ -258,6 +497,37 @@ void DeviceStatusCollector::GetBootMode(
}
}
+void DeviceStatusCollector::GetLocation(
+ em::DeviceStatusReportRequest* request) {
+ em::DeviceLocation* location = request->mutable_device_location();
+ if (!location_helper_) {
+ location->set_error_code(
+ em::DeviceLocation::ERROR_CODE_POSITION_UNAVAILABLE);
+ } else {
+ const Geoposition& position = location_helper_->GetPosition();
+ if (!position.IsValidFix()) {
+ 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());
+ if (position.is_valid_altitude())
+ location->set_altitude(position.altitude);
+ if (position.is_valid_altitude_accuracy())
+ location->set_altitude_accuracy(position.altitude_accuracy);
+ if (position.is_valid_heading())
+ location->set_heading(position.heading);
+ if (position.is_valid_speed())
+ 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 +537,9 @@ void DeviceStatusCollector::GetStatus(em::DeviceStatusReportRequest* request) {
if (report_boot_mode_)
GetBootMode(request);
+
+ if (report_location_)
+ GetLocation(request);
}
void DeviceStatusCollector::OnOSVersion(VersionLoader::Handle handle,

Powered by Google App Engine
This is Rietveld 408576698